1 //=============================================================================
2 //
3 // Adventure Game Studio (AGS)
4 //
5 // Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
6 // The full list of copyright holders can be found in the Copyright.txt
7 // file, which is part of this source code distribution.
8 //
9 // The AGS source code is provided under the Artistic License 2.0.
10 // A copy of this license can be found in the file License.txt and at
11 // http://www.opensource.org/licenses/artistic-license-2.0.php
12 //
13 //=============================================================================
14 //
15 // AGS Character functions
16 //
17 //=============================================================================
18 
19 #include "ac/character.h"
20 #include "ac/common.h"
21 #include "ac/gamesetupstruct.h"
22 #include "ac/roomstruct.h"
23 #include "ac/view.h"
24 #include "ac/display.h"
25 #include "ac/draw.h"
26 #include "ac/event.h"
27 #include "ac/game.h"
28 #include "ac/global_audio.h"
29 #include "ac/global_character.h"
30 #include "ac/global_game.h"
31 #include "ac/global_object.h"
32 #include "ac/global_region.h"
33 #include "ac/global_room.h"
34 #include "ac/global_translation.h"
35 #include "ac/gui.h"
36 #include "ac/lipsync.h"
37 #include "ac/mouse.h"
38 #include "ac/object.h"
39 #include "ac/overlay.h"
40 #include "ac/path.h"
41 #include "ac/properties.h"
42 #include "ac/screenoverlay.h"
43 #include "ac/string.h"
44 #include "ac/system.h"
45 #include "ac/viewframe.h"
46 #include "ac/walkablearea.h"
47 #include "gui/guimain.h"
48 #include "ac/route_finder.h"
49 #include "ac/gamestate.h"
50 #include "debug/debug_log.h"
51 #include "main/game_run.h"
52 #include "main/update.h"
53 #include "ac/spritecache.h"
54 #include "util/string_utils.h"
55 #include <math.h>
56 #include "gfx/graphicsdriver.h"
57 #include "platform/base/override_defines.h"
58 #include "script/runtimescriptvalue.h"
59 #include "ac/dynobj/cc_character.h"
60 #include "ac/dynobj/cc_inventory.h"
61 #include "script/script_runtime.h"
62 #include "gfx/gfx_def.h"
63 
64 using namespace AGS::Common;
65 
66 extern GameSetupStruct game;
67 extern int displayed_room,starting_room;
68 extern roomstruct thisroom;
69 extern MoveList *mls;
70 extern ViewStruct*views;
71 extern RoomObject*objs;
72 extern int spritewidth[MAX_SPRITES],spriteheight[MAX_SPRITES];
73 extern ScriptInvItem scrInv[MAX_INV];
74 extern SpriteCache spriteset;
75 extern ScreenOverlay screenover[MAX_SCREEN_OVERLAYS];
76 extern Bitmap *walkable_areas_temp;
77 extern IGraphicsDriver *gfxDriver;
78 extern Bitmap **actsps;
79 extern int offsetx, offsety;
80 extern int is_text_overlay;
81 extern int said_speech_line;
82 extern int numscreenover;
83 extern int said_text;
84 extern int our_eip;
85 extern int update_music_at;
86 extern int current_screen_resolution_multiplier;
87 extern int cur_mode;
88 extern int screen_is_dirty;
89 extern CCCharacter ccDynamicCharacter;
90 extern CCInventory ccDynamicInv;
91 
92 //--------------------------------
93 
94 
95 CharacterExtras *charextra;
96 CharacterInfo*playerchar;
97 int32_t _sc_PlayerCharPtr = 0;
98 int char_lowest_yp;
99 
100 // Sierra-style speech settings
101 int face_talking=-1,facetalkview=0,facetalkwait=0,facetalkframe=0;
102 int facetalkloop=0, facetalkrepeat = 0, facetalkAllowBlink = 1;
103 int facetalkBlinkLoop = 0;
104 CharacterInfo *facetalkchar = NULL;
105 // Do override default portrait position during QFG4-style speech overlay update
106 bool facetalk_qfg4_override_placement_x = false;
107 bool facetalk_qfg4_override_placement_y = false;
108 
109 // lip-sync speech settings
110 int loops_per_character, text_lips_offset, char_speaking = -1;
111 int char_thinking = -1;
112 const char *text_lips_text = NULL;
113 SpeechLipSyncLine *splipsync = NULL;
114 int numLipLines = 0, curLipLine = -1, curLipLinePhoneme = 0;
115 
116 // **** CHARACTER: FUNCTIONS ****
117 
Character_AddInventory(CharacterInfo * chaa,ScriptInvItem * invi,int addIndex)118 void Character_AddInventory(CharacterInfo *chaa, ScriptInvItem *invi, int addIndex) {
119     int ee;
120 
121     if (invi == NULL)
122         quit("!AddInventoryToCharacter: invalid invnetory number");
123 
124     int inum = invi->id;
125 
126     if (chaa->inv[inum] >= 32000)
127         quit("!AddInventory: cannot carry more than 32000 of one inventory item");
128 
129     chaa->inv[inum]++;
130 
131     int charid = chaa->index_id;
132 
133     if (game.options[OPT_DUPLICATEINV] == 0) {
134         // Ensure it is only in the list once
135         for (ee = 0; ee < charextra[charid].invorder_count; ee++) {
136             if (charextra[charid].invorder[ee] == inum) {
137                 // They already have the item, so don't add it to the list
138                 if (chaa == playerchar)
139                     run_on_event (GE_ADD_INV, RuntimeScriptValue().SetInt32(inum));
140                 return;
141             }
142         }
143     }
144     if (charextra[charid].invorder_count >= MAX_INVORDER)
145         quit("!Too many inventory items added, max 500 display at one time");
146 
147     if ((addIndex == SCR_NO_VALUE) ||
148         (addIndex >= charextra[charid].invorder_count) ||
149         (addIndex < 0)) {
150             // add new item at end of list
151             charextra[charid].invorder[charextra[charid].invorder_count] = inum;
152     }
153     else {
154         // insert new item at index
155         for (ee = charextra[charid].invorder_count - 1; ee >= addIndex; ee--)
156             charextra[charid].invorder[ee + 1] = charextra[charid].invorder[ee];
157 
158         charextra[charid].invorder[addIndex] = inum;
159     }
160     charextra[charid].invorder_count++;
161     guis_need_update = 1;
162     if (chaa == playerchar)
163         run_on_event (GE_ADD_INV, RuntimeScriptValue().SetInt32(inum));
164 
165 }
166 
Character_AddWaypoint(CharacterInfo * chaa,int x,int y)167 void Character_AddWaypoint(CharacterInfo *chaa, int x, int y) {
168 
169     if (chaa->room != displayed_room)
170         quit("!MoveCharacterPath: specified character not in current room");
171 
172     // not already walking, so just do a normal move
173     if (chaa->walking <= 0) {
174         Character_Walk(chaa, x, y, IN_BACKGROUND, ANYWHERE);
175         return;
176     }
177 
178     MoveList *cmls = &mls[chaa->walking % TURNING_AROUND];
179     if (cmls->numstage >= MAXNEEDSTAGES)
180         quit("!MoveCharacterPath: move is too complex, cannot add any further paths");
181 
182     cmls->pos[cmls->numstage] = (x << 16) + y;
183     // They're already walking there anyway
184     if (cmls->pos[cmls->numstage] == cmls->pos[cmls->numstage - 1])
185         return;
186 
187     calculate_move_stage (cmls, cmls->numstage-1);
188     cmls->numstage ++;
189 
190 }
191 
Character_Animate(CharacterInfo * chaa,int loop,int delay,int repeat,int blocking,int direction)192 void Character_Animate(CharacterInfo *chaa, int loop, int delay, int repeat, int blocking, int direction) {
193 
194     if (direction == FORWARDS)
195         direction = 0;
196     else if (direction == BACKWARDS)
197         direction = 1;
198     else
199         quit("!Character.Animate: Invalid DIRECTION parameter");
200 
201     animate_character(chaa, loop, delay, repeat, 0, direction);
202 
203     if ((blocking == BLOCKING) || (blocking == 1))
204         GameLoopUntilEvent(UNTIL_SHORTIS0,(long)&chaa->animating);
205     else if ((blocking != IN_BACKGROUND) && (blocking != 0))
206         quit("!Character.Animate: Invalid BLOCKING parameter");
207 }
208 
Character_ChangeRoomAutoPosition(CharacterInfo * chaa,int room,int newPos)209 void Character_ChangeRoomAutoPosition(CharacterInfo *chaa, int room, int newPos)
210 {
211     if (chaa->index_id != game.playercharacter)
212     {
213         quit("!Character.ChangeRoomAutoPosition can only be used with the player character.");
214     }
215 
216     new_room_pos = newPos;
217 
218     if (new_room_pos == 0) {
219         // auto place on other side of screen
220         if (chaa->x <= thisroom.left + 10)
221             new_room_pos = 2000;
222         else if (chaa->x >= thisroom.right - 10)
223             new_room_pos = 1000;
224         else if (chaa->y <= thisroom.top + 10)
225             new_room_pos = 3000;
226         else if (chaa->y >= thisroom.bottom - 10)
227             new_room_pos = 4000;
228 
229         if (new_room_pos < 3000)
230             new_room_pos += chaa->y;
231         else
232             new_room_pos += chaa->x;
233     }
234     NewRoom(room);
235 }
236 
Character_ChangeRoom(CharacterInfo * chaa,int room,int x,int y)237 void Character_ChangeRoom(CharacterInfo *chaa, int room, int x, int y) {
238     Character_ChangeRoomSetLoop(chaa, room, x, y, SCR_NO_VALUE);
239 }
240 
Character_ChangeRoomSetLoop(CharacterInfo * chaa,int room,int x,int y,int direction)241 void Character_ChangeRoomSetLoop(CharacterInfo *chaa, int room, int x, int y, int direction) {
242 
243     if (chaa->index_id != game.playercharacter) {
244         // NewRoomNPC
245         if ((x != SCR_NO_VALUE) && (y != SCR_NO_VALUE)) {
246             chaa->x = x;
247             chaa->y = y;
248 			if (direction != SCR_NO_VALUE && direction>=0) chaa->loop = direction;
249         }
250         chaa->prevroom = chaa->room;
251         chaa->room = room;
252 
253 		debug_script_log("%s moved to room %d, location %d,%d, loop %d",
254 			chaa->scrname, room, chaa->x, chaa->y, chaa->loop);
255 
256         return;
257     }
258 
259     if ((x != SCR_NO_VALUE) && (y != SCR_NO_VALUE)) {
260         new_room_pos = 0;
261 
262         if (loaded_game_file_version <= kGameVersion_272)
263         {
264             // Set position immediately on 2.x.
265             chaa->x = x;
266             chaa->y = y;
267         }
268         else
269         {
270             // don't check X or Y bounds, so that they can do a
271             // walk-in animation if they want
272             new_room_x = x;
273             new_room_y = y;
274 			if (direction != SCR_NO_VALUE) new_room_loop = direction;
275         }
276     }
277 
278     NewRoom(room);
279 }
280 
281 
Character_ChangeView(CharacterInfo * chap,int vii)282 void Character_ChangeView(CharacterInfo *chap, int vii) {
283     vii--;
284 
285     if ((vii < 0) || (vii >= game.numviews))
286         quit("!ChangeCharacterView: invalid view number specified");
287 
288     // if animating, but not idle view, give warning message
289     if ((chap->flags & CHF_FIXVIEW) && (chap->idleleft >= 0))
290         debug_script_warn("Warning: ChangeCharacterView was used while the view was fixed - call ReleaseCharView first");
291 
292     // if the idle animation is playing we should release the view
293     if ( chap->idleleft < 0) {
294       Character_UnlockView(chap);
295       chap->idleleft = chap->idletime;
296     }
297 
298     debug_script_log("%s: Change view to %d", chap->scrname, vii+1);
299     chap->defview = vii;
300     chap->view = vii;
301     chap->animating = 0;
302     chap->frame = 0;
303     chap->wait = 0;
304     chap->walkwait = 0;
305     charextra[chap->index_id].animwait = 0;
306     FindReasonableLoopForCharacter(chap);
307 }
308 
309 enum DirectionalLoop
310 {
311     kDirLoop_Down      = 0,
312     kDirLoop_Left      = 1,
313     kDirLoop_Right     = 2,
314     kDirLoop_Up        = 3,
315     kDirLoop_DownRight = 4,
316     kDirLoop_UpRight   = 5,
317     kDirLoop_DownLeft  = 6,
318     kDirLoop_UpLeft    = 7,
319 
320     kDirLoop_Default        = kDirLoop_Down,
321     kDirLoop_LastOrthogonal = kDirLoop_Up,
322     kDirLoop_Last           = kDirLoop_UpLeft,
323 };
324 
325 // Internal direction-facing functions
326 
GetDirectionalLoop(CharacterInfo * chinfo,int x_diff,int y_diff)327 DirectionalLoop GetDirectionalLoop(CharacterInfo *chinfo, int x_diff, int y_diff)
328 {
329     DirectionalLoop next_loop = kDirLoop_Left; // NOTE: default loop was Left for some reason
330 
331     const ViewStruct &chview  = views[chinfo->view];
332     const bool new_version    = loaded_game_file_version > kGameVersion_272;
333     const bool has_down_loop  = ((chview.numLoops > kDirLoop_Down)  && (chview.loops[kDirLoop_Down].numFrames > 0));
334     const bool has_up_loop    = ((chview.numLoops > kDirLoop_Up)    && (chview.loops[kDirLoop_Up].numFrames > 0));
335     // NOTE: 3.+ games required left & right loops to be present at all times
336     const bool has_left_loop  = new_version ||
337                                 ((chview.numLoops > kDirLoop_Left)  && (chview.loops[kDirLoop_Left].numFrames > 0));
338     const bool has_right_loop = new_version ||
339                                 ((chview.numLoops > kDirLoop_Right) && (chview.loops[kDirLoop_Right].numFrames > 0));
340     const bool has_diagonal_loops = useDiagonal(chinfo) == 0; // NOTE: useDiagonal returns 0 for "true"
341 
342     const bool want_horizontal = (abs(y_diff) < abs(x_diff)) ||
343         new_version && (!has_down_loop || !has_up_loop) ||
344         // NOTE: <= 2.72 games switch to horizontal loops only if both vertical ones are missing
345         !new_version && (!has_down_loop && !has_up_loop);
346     if (want_horizontal)
347     {
348         const bool want_diagonal = has_diagonal_loops && (abs(y_diff) > abs(x_diff) / 2);
349         if (!has_left_loop && !has_right_loop)
350         {
351             next_loop = kDirLoop_Down;
352         }
353         else if (has_right_loop && (x_diff > 0))
354         {
355             next_loop = want_diagonal ? (y_diff < 0 ? kDirLoop_UpRight : kDirLoop_DownRight) :
356                 kDirLoop_Right;
357         }
358         else if (has_left_loop && (x_diff <= 0))
359         {
360             next_loop = want_diagonal ? (y_diff < 0 ? kDirLoop_UpLeft : kDirLoop_DownLeft) :
361                 kDirLoop_Left;
362         }
363     }
364     else
365     {
366         const bool want_diagonal = has_diagonal_loops && (abs(x_diff) > abs(y_diff) / 2);
367         if (y_diff > 0 || !has_up_loop)
368         {
369             next_loop = want_diagonal ? (x_diff < 0 ? kDirLoop_DownLeft : kDirLoop_DownRight) :
370                 kDirLoop_Down;
371         }
372         else
373         {
374             next_loop = want_diagonal ? (x_diff < 0 ? kDirLoop_UpLeft : kDirLoop_UpRight) :
375                 kDirLoop_Up;
376         }
377     }
378     return next_loop;
379 }
380 
FaceDirectionalLoop(CharacterInfo * char1,int direction,int blockingStyle)381 void FaceDirectionalLoop(CharacterInfo *char1, int direction, int blockingStyle)
382 {
383     // Change facing only if the desired direction is different
384     if (direction != char1->loop)
385     {
386         if ((game.options[OPT_TURNTOFACELOC] != 0) &&
387             (in_enters_screen == 0))
388         {
389             const int no_diagonal = useDiagonal (char1);
390             const int highestLoopForTurning = no_diagonal != 1 ? kDirLoop_Last : kDirLoop_LastOrthogonal;
391             if ((char1->loop <= highestLoopForTurning))
392             {
393                 // Turn to face new direction
394                 Character_StopMoving(char1);
395                 if (char1->on == 1)
396                 {
397                     // only do the turning if the character is not hidden
398                     // (otherwise GameLoopUntilEvent will never return)
399                     start_character_turning (char1, direction, no_diagonal);
400 
401                     if ((blockingStyle == BLOCKING) || (blockingStyle == 1))
402                         GameLoopUntilEvent(UNTIL_MOVEEND, (long) &char1->walking);
403                 }
404                 else
405                     char1->loop = direction;
406             }
407             else
408                 char1->loop = direction;
409         }
410         else
411             char1->loop = direction;
412     }
413 
414     char1->frame = 0;
415 }
416 
FaceLocationXY(CharacterInfo * char1,int xx,int yy,int blockingStyle)417 void FaceLocationXY(CharacterInfo *char1, int xx, int yy, int blockingStyle)
418 {
419     debug_script_log("%s: Face location %d,%d", char1->scrname, xx, yy);
420 
421     const int diffrx = xx - char1->x;
422     const int diffry = yy - char1->y;
423 
424     if ((diffrx == 0) && (diffry == 0)) {
425         // FaceLocation called on their current position - do nothing
426         return;
427     }
428 
429     FaceDirectionalLoop(char1, GetDirectionalLoop(char1, diffrx, diffry), blockingStyle);
430 }
431 
432 // External direction-facing functions with validation
433 
Character_FaceDirection(CharacterInfo * char1,int direction,int blockingStyle)434 void Character_FaceDirection(CharacterInfo *char1, int direction, int blockingStyle)
435 {
436     if (char1 == NULL)
437         quit("!FaceDirection: invalid character specified");
438 
439     if (direction != SCR_NO_VALUE)
440     {
441         if (direction < 0 || direction > kDirLoop_Last)
442             quit("!FaceDirection: invalid direction specified");
443 
444         FaceDirectionalLoop(char1, direction, blockingStyle);
445     }
446 }
447 
Character_FaceLocation(CharacterInfo * char1,int xx,int yy,int blockingStyle)448 void Character_FaceLocation(CharacterInfo *char1, int xx, int yy, int blockingStyle)
449 {
450     if (char1 == NULL)
451         quit("!FaceLocation: invalid character specified");
452 
453     FaceLocationXY(char1, xx, yy, blockingStyle);
454 }
455 
Character_FaceObject(CharacterInfo * char1,ScriptObject * obj,int blockingStyle)456 void Character_FaceObject(CharacterInfo *char1, ScriptObject *obj, int blockingStyle) {
457     if (obj == NULL)
458         quit("!FaceObject: invalid object specified");
459 
460     FaceLocationXY(char1, objs[obj->id].x, objs[obj->id].y, blockingStyle);
461 }
462 
Character_FaceCharacter(CharacterInfo * char1,CharacterInfo * char2,int blockingStyle)463 void Character_FaceCharacter(CharacterInfo *char1, CharacterInfo *char2, int blockingStyle) {
464     if (char2 == NULL)
465         quit("!FaceCharacter: invalid character specified");
466 
467     if (char1->room != char2->room)
468         quit("!FaceCharacter: characters are in different rooms");
469 
470     FaceLocationXY(char1, char2->x, char2->y, blockingStyle);
471 }
472 
Character_FollowCharacter(CharacterInfo * chaa,CharacterInfo * tofollow,int distaway,int eagerness)473 void Character_FollowCharacter(CharacterInfo *chaa, CharacterInfo *tofollow, int distaway, int eagerness) {
474 
475     if ((eagerness < 0) || (eagerness > 250))
476         quit("!FollowCharacterEx: invalid eagerness: must be 0-250");
477 
478     if ((chaa->index_id == game.playercharacter) && (tofollow != NULL) &&
479         (tofollow->room != chaa->room))
480         quit("!FollowCharacterEx: you cannot tell the player character to follow a character in another room");
481 
482     if (tofollow != NULL) {
483         debug_script_log("%s: Start following %s (dist %d, eager %d)", chaa->scrname, tofollow->scrname, distaway, eagerness);
484     }
485     else {
486         debug_script_log("%s: Stop following other character", chaa->scrname);
487     }
488 
489     if ((chaa->following >= 0) &&
490         (chaa->followinfo == FOLLOW_ALWAYSONTOP)) {
491             // if this character was following always-on-top, its baseline will
492             // have been changed, so release it.
493             chaa->baseline = -1;
494     }
495 
496     if (tofollow == NULL)
497         chaa->following = -1;
498     else
499         chaa->following = tofollow->index_id;
500 
501     chaa->followinfo=(distaway << 8) | eagerness;
502 
503     chaa->flags &= ~CHF_BEHINDSHEPHERD;
504 
505     // special case for Always On Other Character
506     if (distaway == FOLLOW_ALWAYSONTOP) {
507         chaa->followinfo = FOLLOW_ALWAYSONTOP;
508         if (eagerness == 1)
509             chaa->flags |= CHF_BEHINDSHEPHERD;
510     }
511 
512     if (chaa->animating & CHANIM_REPEAT)
513         debug_script_warn("Warning: FollowCharacter called but the sheep is currently animating looped. It may never start to follow.");
514 
515 }
516 
Character_IsCollidingWithChar(CharacterInfo * char1,CharacterInfo * char2)517 int Character_IsCollidingWithChar(CharacterInfo *char1, CharacterInfo *char2) {
518     if (char2 == NULL)
519         quit("!AreCharactersColliding: invalid char2");
520 
521     if (char1->room != char2->room) return 0; // not colliding
522 
523     if ((char1->y > char2->y - 5) && (char1->y < char2->y + 5)) ;
524     else return 0;
525 
526     int w1 = divide_down_coordinate(GetCharacterWidth(char1->index_id));
527     int w2 = divide_down_coordinate(GetCharacterWidth(char2->index_id));
528 
529     int xps1=char1->x - w1/2;
530     int xps2=char2->x - w2/2;
531 
532     if ((xps1 >= xps2 - w1) & (xps1 <= xps2 + w2)) return 1;
533     return 0;
534 }
535 
Character_IsCollidingWithObject(CharacterInfo * chin,ScriptObject * objid)536 int Character_IsCollidingWithObject(CharacterInfo *chin, ScriptObject *objid) {
537     if (objid == NULL)
538         quit("!AreCharObjColliding: invalid object number");
539 
540     if (chin->room != displayed_room)
541         return 0;
542     if (objs[objid->id].on != 1)
543         return 0;
544 
545     Bitmap *checkblk = GetObjectImage(objid->id, NULL);
546     int objWidth = checkblk->GetWidth();
547     int objHeight = checkblk->GetHeight();
548     int o1x = objs[objid->id].x;
549     int o1y = objs[objid->id].y - divide_down_coordinate(objHeight);
550 
551     Bitmap *charpic = GetCharacterImage(chin->index_id, NULL);
552 
553     int charWidth = charpic->GetWidth();
554     int charHeight = charpic->GetHeight();
555     int o2x = chin->x - divide_down_coordinate(charWidth) / 2;
556     int o2y = chin->get_effective_y() - 5;  // only check feet
557 
558     if ((o2x >= o1x - divide_down_coordinate(charWidth)) &&
559         (o2x <= o1x + divide_down_coordinate(objWidth)) &&
560         (o2y >= o1y - 8) &&
561         (o2y <= o1y + divide_down_coordinate(objHeight))) {
562             // the character's feet are on the object
563             if (game.options[OPT_PIXPERFECT] == 0)
564                 return 1;
565             // check if they're on a transparent bit of the object
566             int stxp = multiply_up_coordinate(o2x - o1x);
567             int styp = multiply_up_coordinate(o2y - o1y);
568             int maskcol = checkblk->GetMaskColor ();
569             int maskcolc = charpic->GetMaskColor ();
570             int thispix, thispixc;
571             // check each pixel of the object along the char's feet
572             for (int i = 0; i < charWidth; i += get_fixed_pixel_size(1)) {
573                 for (int j = 0; j < get_fixed_pixel_size(6); j += get_fixed_pixel_size(1)) {
574                     thispix = my_getpixel(checkblk, i + stxp, j + styp);
575                     thispixc = my_getpixel(charpic, i, j + (charHeight - get_fixed_pixel_size(5)));
576 
577                     if ((thispix != -1) && (thispix != maskcol) &&
578                         (thispixc != -1) && (thispixc != maskcolc))
579                         return 1;
580                 }
581             }
582 
583     }
584     return 0;
585 }
586 
Character_IsInteractionAvailable(CharacterInfo * cchar,int mood)587 bool Character_IsInteractionAvailable(CharacterInfo *cchar, int mood) {
588 
589     play.check_interaction_only = 1;
590     RunCharacterInteraction(cchar->index_id, mood);
591     int ciwas = play.check_interaction_only;
592     play.check_interaction_only = 0;
593     return (ciwas == 2);
594 }
595 
Character_LockView(CharacterInfo * chap,int vii)596 void Character_LockView(CharacterInfo *chap, int vii) {
597     Character_LockViewEx(chap, vii, STOP_MOVING);
598 }
599 
Character_LockViewEx(CharacterInfo * chap,int vii,int stopMoving)600 void Character_LockViewEx(CharacterInfo *chap, int vii, int stopMoving) {
601 
602     if ((vii < 1) || (vii > game.numviews)) {
603         char buffer[150];
604         sprintf (buffer, "!SetCharacterView: invalid view number (You said %d, max is %d)", vii, game.numviews);
605         quit(buffer);
606     }
607     vii--;
608 
609     debug_script_log("%s: View locked to %d", chap->scrname, vii+1);
610     if (chap->idleleft < 0) {
611         Character_UnlockView(chap);
612         chap->idleleft = chap->idletime;
613     }
614     if (stopMoving != KEEP_MOVING)
615     {
616         Character_StopMoving(chap);
617     }
618     chap->view=vii;
619     chap->animating=0;
620     FindReasonableLoopForCharacter(chap);
621     chap->frame=0;
622     chap->wait=0;
623     chap->flags|=CHF_FIXVIEW;
624     chap->pic_xoffs = 0;
625     chap->pic_yoffs = 0;
626 }
627 
Character_LockViewAligned(CharacterInfo * chap,int vii,int loop,int align)628 void Character_LockViewAligned(CharacterInfo *chap, int vii, int loop, int align) {
629     Character_LockViewAlignedEx(chap, vii, loop, align, STOP_MOVING);
630 }
631 
Character_LockViewAlignedEx(CharacterInfo * chap,int vii,int loop,int align,int stopMoving)632 void Character_LockViewAlignedEx(CharacterInfo *chap, int vii, int loop, int align, int stopMoving) {
633     if (chap->view < 0)
634         quit("!SetCharacterLoop: character has invalid old view number");
635 
636     int sppic = views[chap->view].loops[chap->loop].frames[chap->frame].pic;
637     int leftSide = multiply_up_coordinate(chap->x) - spritewidth[sppic] / 2;
638 
639     Character_LockViewEx(chap, vii, stopMoving);
640 
641     if ((loop < 0) || (loop >= views[chap->view].numLoops))
642         quit("!SetCharacterViewEx: invalid loop specified");
643 
644     chap->loop = loop;
645     chap->frame = 0;
646     int newpic = views[chap->view].loops[chap->loop].frames[chap->frame].pic;
647     int newLeft = multiply_up_coordinate(chap->x) - spritewidth[newpic] / 2;
648     int xdiff = 0;
649 
650     if (align == SCALIGN_LEFT)
651         xdiff = leftSide - newLeft;
652     else if (align == SCALIGN_CENTRE)
653         xdiff = 0;
654     else if (align == SCALIGN_RIGHT)
655         xdiff = (leftSide + spritewidth[sppic]) - (newLeft + spritewidth[newpic]);
656     else
657         quit("!SetCharacterViewEx: invalid alignment type specified");
658 
659     chap->pic_xoffs = xdiff;
660     chap->pic_yoffs = 0;
661 }
662 
Character_LockViewFrame(CharacterInfo * chaa,int view,int loop,int frame)663 void Character_LockViewFrame(CharacterInfo *chaa, int view, int loop, int frame) {
664     Character_LockViewFrameEx(chaa, view, loop, frame, STOP_MOVING);
665 }
666 
Character_LockViewFrameEx(CharacterInfo * chaa,int view,int loop,int frame,int stopMoving)667 void Character_LockViewFrameEx(CharacterInfo *chaa, int view, int loop, int frame, int stopMoving) {
668 
669     Character_LockViewEx(chaa, view, stopMoving);
670 
671     view--;
672     if ((loop < 0) || (loop >= views[view].numLoops))
673         quit("!SetCharacterFrame: invalid loop specified");
674     if ((frame < 0) || (frame >= views[view].loops[loop].numFrames))
675         quit("!SetCharacterFrame: invalid frame specified");
676 
677     chaa->loop = loop;
678     chaa->frame = frame;
679 }
680 
Character_LockViewOffset(CharacterInfo * chap,int vii,int xoffs,int yoffs)681 void Character_LockViewOffset(CharacterInfo *chap, int vii, int xoffs, int yoffs) {
682     Character_LockViewOffsetEx(chap, vii, xoffs, yoffs, STOP_MOVING);
683 }
684 
Character_LockViewOffsetEx(CharacterInfo * chap,int vii,int xoffs,int yoffs,int stopMoving)685 void Character_LockViewOffsetEx(CharacterInfo *chap, int vii, int xoffs, int yoffs, int stopMoving) {
686     Character_LockViewEx(chap, vii, stopMoving);
687 
688     if ((current_screen_resolution_multiplier == 1) && (game.IsHiRes())) {
689         // running a 640x400 game at 320x200, adjust
690         xoffs /= 2;
691         yoffs /= 2;
692     }
693     else if ((current_screen_resolution_multiplier > 1) && (!game.IsHiRes())) {
694         // running a 320x200 game at 640x400, adjust
695         xoffs *= 2;
696         yoffs *= 2;
697     }
698 
699     chap->pic_xoffs = xoffs;
700     chap->pic_yoffs = yoffs;
701 }
702 
Character_LoseInventory(CharacterInfo * chap,ScriptInvItem * invi)703 void Character_LoseInventory(CharacterInfo *chap, ScriptInvItem *invi) {
704 
705     if (invi == NULL)
706         quit("!LoseInventoryFromCharacter: invalid invnetory number");
707 
708     int inum = invi->id;
709 
710     if (chap->inv[inum] > 0)
711         chap->inv[inum]--;
712 
713     if ((chap->activeinv == inum) & (chap->inv[inum] < 1)) {
714         chap->activeinv = -1;
715         if ((chap == playerchar) && (GetCursorMode() == MODE_USE))
716             set_cursor_mode(0);
717     }
718 
719     int charid = chap->index_id;
720 
721     if ((chap->inv[inum] == 0) || (game.options[OPT_DUPLICATEINV] > 0)) {
722         int xx,tt;
723         for (xx = 0; xx < charextra[charid].invorder_count; xx++) {
724             if (charextra[charid].invorder[xx] == inum) {
725                 charextra[charid].invorder_count--;
726                 for (tt = xx; tt < charextra[charid].invorder_count; tt++)
727                     charextra[charid].invorder[tt] = charextra[charid].invorder[tt+1];
728                 break;
729             }
730         }
731     }
732     guis_need_update = 1;
733 
734     if (chap == playerchar)
735         run_on_event (GE_LOSE_INV, RuntimeScriptValue().SetInt32(inum));
736 }
737 
Character_PlaceOnWalkableArea(CharacterInfo * chap)738 void Character_PlaceOnWalkableArea(CharacterInfo *chap)
739 {
740     if (displayed_room < 0)
741         quit("!Character.PlaceOnWalkableArea: no room is currently loaded");
742 
743     find_nearest_walkable_area(&chap->x, &chap->y);
744 }
745 
Character_RemoveTint(CharacterInfo * chaa)746 void Character_RemoveTint(CharacterInfo *chaa) {
747 
748     if (chaa->flags & (CHF_HASTINT | CHF_HASLIGHT)) {
749         debug_script_log("Un-tint %s", chaa->scrname);
750         chaa->flags &= ~(CHF_HASTINT | CHF_HASLIGHT);
751     }
752     else {
753         debug_script_warn("Character.RemoveTint called but character was not tinted");
754     }
755 }
756 
Character_GetHasExplicitTint(CharacterInfo * ch)757 int Character_GetHasExplicitTint(CharacterInfo *ch)
758 {
759     return ch->has_explicit_tint() || ((game.options[OPT_BASESCRIPTAPI] < kScriptAPI_v341) && ch->has_explicit_light());
760 }
761 
Character_Say(CharacterInfo * chaa,const char * text)762 void Character_Say(CharacterInfo *chaa, const char *text) {
763     _DisplaySpeechCore(chaa->index_id, text);
764 }
765 
Character_SayAt(CharacterInfo * chaa,int x,int y,int width,const char * texx)766 void Character_SayAt(CharacterInfo *chaa, int x, int y, int width, const char *texx) {
767 
768     DisplaySpeechAt(x, y, width, chaa->index_id, (char*)texx);
769 }
770 
Character_SayBackground(CharacterInfo * chaa,const char * texx)771 ScriptOverlay* Character_SayBackground(CharacterInfo *chaa, const char *texx) {
772 
773     int ovltype = DisplaySpeechBackground(chaa->index_id, (char*)texx);
774     int ovri = find_overlay_of_type(ovltype);
775     if (ovri<0)
776         quit("!SayBackground internal error: no overlay");
777 
778     // Convert the overlay ID to an Overlay object
779     ScriptOverlay *scOver = new ScriptOverlay();
780     scOver->overlayId = ovltype;
781     scOver->borderHeight = 0;
782     scOver->borderWidth = 0;
783     scOver->isBackgroundSpeech = 1;
784     int handl = ccRegisterManagedObject(scOver, scOver);
785     screenover[ovri].associatedOverlayHandle = handl;
786 
787     return scOver;
788 }
789 
Character_SetAsPlayer(CharacterInfo * chaa)790 void Character_SetAsPlayer(CharacterInfo *chaa) {
791 
792     // Set to same character, so ignore.
793     // But only on versions > 2.61. The relevant entry in the 2.62 changelog is:
794     //  - Fixed SetPlayerCharacter to do nothing at all if you pass the current
795     //    player character to it (previously it was resetting the inventory layout)
796     if ((loaded_game_file_version > kGameVersion_261) && (game.playercharacter == chaa->index_id))
797         return;
798 
799     setup_player_character(chaa->index_id);
800 
801     //update_invorder();
802 
803     debug_script_log("%s is new player character", playerchar->scrname);
804 
805     // Within game_start, return now
806     if (displayed_room < 0)
807         return;
808 
809     // Ignore invalid room numbers for the character and just place him in
810     // the current room for 2.x. Following script calls to NewRoom() will
811     // make sure this still works as intended.
812     if ((loaded_game_file_version <= kGameVersion_272) && (playerchar->room < 0))
813         playerchar->room = displayed_room;
814 
815     if (displayed_room != playerchar->room)
816         NewRoom(playerchar->room);
817     else   // make sure it doesn't run the region interactions
818         play.player_on_region = GetRegionAt (playerchar->x, playerchar->y);
819 
820     if ((playerchar->activeinv >= 0) && (playerchar->inv[playerchar->activeinv] < 1))
821         playerchar->activeinv = -1;
822 
823     // They had inv selected, so change the cursor
824     if (cur_mode == MODE_USE) {
825         if (playerchar->activeinv < 0)
826             SetNextCursor ();
827         else
828             SetActiveInventory (playerchar->activeinv);
829     }
830 
831 }
832 
833 
Character_SetIdleView(CharacterInfo * chaa,int iview,int itime)834 void Character_SetIdleView(CharacterInfo *chaa, int iview, int itime) {
835 
836     if (iview == 1)
837         quit("!SetCharacterIdle: view 1 cannot be used as an idle view, sorry.");
838 
839     // if an idle anim is currently playing, release it
840     if (chaa->idleleft < 0)
841         Character_UnlockView(chaa);
842 
843     chaa->idleview = iview - 1;
844     // make sure they don't appear idle while idle anim is disabled
845     if (iview < 1)
846         itime = 10;
847     chaa->idletime = itime;
848     chaa->idleleft = itime;
849 
850     // if not currently animating, reset the wait counter
851     if ((chaa->animating == 0) && (chaa->walking == 0))
852         chaa->wait = 0;
853 
854     if (iview >= 1) {
855         debug_script_log("Set %s idle view to %d (time %d)", chaa->scrname, iview, itime);
856     }
857     else {
858         debug_script_log("%s idle view disabled", chaa->scrname);
859     }
860     if (chaa->flags & CHF_FIXVIEW) {
861         debug_script_warn("SetCharacterIdle called while character view locked with SetCharacterView; idle ignored");
862         debug_script_log("View locked, idle will not kick in until Released");
863     }
864     // if they switch to a swimming animation, kick it off immediately
865     if (itime == 0)
866         charextra[chaa->index_id].process_idle_this_time = 1;
867 
868 }
869 
Character_GetHasExplicitLight(CharacterInfo * ch)870 bool Character_GetHasExplicitLight(CharacterInfo *ch)
871 {
872     return ch->has_explicit_light();
873 }
874 
Character_GetLightLevel(CharacterInfo * ch)875 int Character_GetLightLevel(CharacterInfo *ch)
876 {
877     return ch->has_explicit_light() ? charextra[ch->index_id].tint_light : 0;
878 }
879 
Character_SetLightLevel(CharacterInfo * chaa,int light_level)880 void Character_SetLightLevel(CharacterInfo *chaa, int light_level)
881 {
882     light_level = Math::Clamp(-100, 100, light_level);
883 
884     charextra[chaa->index_id].tint_light = light_level;
885     chaa->flags &= ~CHF_HASTINT;
886     chaa->flags |= CHF_HASLIGHT;
887 }
888 
Character_GetTintRed(CharacterInfo * ch)889 int Character_GetTintRed(CharacterInfo *ch)
890 {
891     return ch->has_explicit_tint() ? charextra[ch->index_id].tint_r : 0;
892 }
893 
Character_GetTintGreen(CharacterInfo * ch)894 int Character_GetTintGreen(CharacterInfo *ch)
895 {
896     return ch->has_explicit_tint() ? charextra[ch->index_id].tint_g : 0;
897 }
898 
Character_GetTintBlue(CharacterInfo * ch)899 int Character_GetTintBlue(CharacterInfo *ch)
900 {
901     return ch->has_explicit_tint() ? charextra[ch->index_id].tint_b : 0;
902 }
903 
Character_GetTintSaturation(CharacterInfo * ch)904 int Character_GetTintSaturation(CharacterInfo *ch)
905 {
906     return ch->has_explicit_tint() ? charextra[ch->index_id].tint_level : 0;
907 }
908 
Character_GetTintLuminance(CharacterInfo * ch)909 int Character_GetTintLuminance(CharacterInfo *ch)
910 {
911     return ch->has_explicit_tint() ? ((charextra[ch->index_id].tint_light * 10) / 25) : 0;
912 }
913 
Character_SetOption(CharacterInfo * chaa,int flag,int yesorno)914 void Character_SetOption(CharacterInfo *chaa, int flag, int yesorno) {
915 
916     if ((yesorno < 0) || (yesorno > 1))
917         quit("!SetCharacterProperty: last parameter must be 0 or 1");
918 
919     if (flag & CHF_MANUALSCALING) {
920         // backwards compatibility fix
921         Character_SetIgnoreScaling(chaa, yesorno);
922     }
923     else {
924         chaa->flags &= ~flag;
925         if (yesorno)
926             chaa->flags |= flag;
927     }
928 
929 }
930 
Character_SetSpeed(CharacterInfo * chaa,int xspeed,int yspeed)931 void Character_SetSpeed(CharacterInfo *chaa, int xspeed, int yspeed) {
932 
933     if ((xspeed == 0) || (xspeed > 50) || (yspeed == 0) || (yspeed > 50))
934         quit("!SetCharacterSpeedEx: invalid speed value");
935     if (chaa->walking)
936         quit("!SetCharacterSpeedEx: cannot change speed while walking");
937 
938     chaa->walkspeed = xspeed;
939 
940     if (yspeed == xspeed)
941         chaa->walkspeed_y = UNIFORM_WALK_SPEED;
942     else
943         chaa->walkspeed_y = yspeed;
944 }
945 
946 
Character_StopMoving(CharacterInfo * charp)947 void Character_StopMoving(CharacterInfo *charp) {
948 
949     int chaa = charp->index_id;
950     if (chaa == play.skip_until_char_stops)
951         EndSkippingUntilCharStops();
952 
953     if (charextra[chaa].xwas != INVALID_X) {
954         charp->x = charextra[chaa].xwas;
955         charp->y = charextra[chaa].ywas;
956         charextra[chaa].xwas = INVALID_X;
957     }
958     if ((charp->walking > 0) && (charp->walking < TURNING_AROUND)) {
959         // if it's not a MoveCharDirect, make sure they end up on a walkable area
960         if ((mls[charp->walking].direct == 0) && (charp->room == displayed_room))
961             Character_PlaceOnWalkableArea(charp);
962 
963         debug_script_log("%s: stop moving", charp->scrname);
964 
965         charp->idleleft = charp->idletime;
966         // restart the idle animation straight away
967         charextra[chaa].process_idle_this_time = 1;
968     }
969     if (charp->walking) {
970         // If the character is currently moving, stop them and reset their frame
971         charp->walking = 0;
972         if ((charp->flags & CHF_MOVENOTWALK) == 0)
973             charp->frame = 0;
974     }
975 }
976 
Character_Tint(CharacterInfo * chaa,int red,int green,int blue,int opacity,int luminance)977 void Character_Tint(CharacterInfo *chaa, int red, int green, int blue, int opacity, int luminance) {
978     if ((red < 0) || (green < 0) || (blue < 0) ||
979         (red > 255) || (green > 255) || (blue > 255) ||
980         (opacity < 0) || (opacity > 100) ||
981         (luminance < 0) || (luminance > 100))
982         quit("!Character.Tint: invalid parameter. R,G,B must be 0-255, opacity & luminance 0-100");
983 
984     debug_script_log("Set %s tint RGB(%d,%d,%d) %d%%", chaa->scrname, red, green, blue, opacity);
985 
986     charextra[chaa->index_id].tint_r = red;
987     charextra[chaa->index_id].tint_g = green;
988     charextra[chaa->index_id].tint_b = blue;
989     charextra[chaa->index_id].tint_level = opacity;
990     charextra[chaa->index_id].tint_light = (luminance * 25) / 10;
991     chaa->flags &= ~CHF_HASLIGHT;
992     chaa->flags |= CHF_HASTINT;
993 }
994 
Character_Think(CharacterInfo * chaa,const char * text)995 void Character_Think(CharacterInfo *chaa, const char *text) {
996     _DisplayThoughtCore(chaa->index_id, text);
997 }
998 
Character_UnlockView(CharacterInfo * chaa)999 void Character_UnlockView(CharacterInfo *chaa) {
1000     Character_UnlockViewEx(chaa, STOP_MOVING);
1001 }
1002 
Character_UnlockViewEx(CharacterInfo * chaa,int stopMoving)1003 void Character_UnlockViewEx(CharacterInfo *chaa, int stopMoving) {
1004     if (chaa->flags & CHF_FIXVIEW) {
1005         debug_script_log("%s: Released view back to default", chaa->scrname);
1006     }
1007     chaa->flags &= ~CHF_FIXVIEW;
1008     chaa->view = chaa->defview;
1009     chaa->frame = 0;
1010     if (stopMoving != KEEP_MOVING)
1011     {
1012         Character_StopMoving(chaa);
1013     }
1014     if (chaa->view >= 0) {
1015         int maxloop = views[chaa->view].numLoops;
1016         if (((chaa->flags & CHF_NODIAGONAL)!=0) && (maxloop > 4))
1017             maxloop = 4;
1018         FindReasonableLoopForCharacter(chaa);
1019     }
1020     chaa->animating = 0;
1021     chaa->idleleft = chaa->idletime;
1022     chaa->pic_xoffs = 0;
1023     chaa->pic_yoffs = 0;
1024     // restart the idle animation straight away
1025     charextra[chaa->index_id].process_idle_this_time = 1;
1026 
1027 }
1028 
1029 
Character_Walk(CharacterInfo * chaa,int x,int y,int blocking,int direct)1030 void Character_Walk(CharacterInfo *chaa, int x, int y, int blocking, int direct)
1031 {
1032     walk_or_move_character(chaa, x, y, blocking, direct, true);
1033 }
1034 
Character_Move(CharacterInfo * chaa,int x,int y,int blocking,int direct)1035 void Character_Move(CharacterInfo *chaa, int x, int y, int blocking, int direct)
1036 {
1037     walk_or_move_character(chaa, x, y, blocking, direct, false);
1038 }
1039 
Character_WalkStraight(CharacterInfo * chaa,int xx,int yy,int blocking)1040 void Character_WalkStraight(CharacterInfo *chaa, int xx, int yy, int blocking) {
1041 
1042     if (chaa->room != displayed_room)
1043         quit("!MoveCharacterStraight: specified character not in current room");
1044 
1045     Character_StopMoving(chaa);
1046     int movetox = xx, movetoy = yy;
1047 
1048     wallscreen = prepare_walkable_areas(chaa->index_id);
1049 
1050     int fromXLowres = convert_to_low_res(chaa->x);
1051     int fromYLowres = convert_to_low_res(chaa->y);
1052     int toXLowres = convert_to_low_res(xx);
1053     int toYLowres = convert_to_low_res(yy);
1054 
1055     if (!can_see_from(fromXLowres, fromYLowres, toXLowres, toYLowres)) {
1056         movetox = convert_back_to_high_res(lastcx);
1057         movetoy = convert_back_to_high_res(lastcy);
1058     }
1059 
1060     walk_character(chaa->index_id, movetox, movetoy, 1, true);
1061 
1062     if ((blocking == BLOCKING) || (blocking == 1))
1063         GameLoopUntilEvent(UNTIL_MOVEEND,(long)&chaa->walking);
1064     else if ((blocking != IN_BACKGROUND) && (blocking != 0))
1065         quit("!Character.Walk: Blocking must be BLOCKING or IN_BACKGRUOND");
1066 
1067 }
1068 
Character_RunInteraction(CharacterInfo * chaa,int mood)1069 void Character_RunInteraction(CharacterInfo *chaa, int mood) {
1070 
1071     RunCharacterInteraction(chaa->index_id, mood);
1072 }
1073 
1074 
1075 
1076 // **** CHARACTER: PROPERTIES ****
1077 
Character_GetProperty(CharacterInfo * chaa,const char * property)1078 int Character_GetProperty(CharacterInfo *chaa, const char *property) {
1079 
1080     return get_int_property(game.charProps[chaa->index_id], play.charProps[chaa->index_id], property);
1081 
1082 }
Character_GetPropertyText(CharacterInfo * chaa,const char * property,char * bufer)1083 void Character_GetPropertyText(CharacterInfo *chaa, const char *property, char *bufer) {
1084     get_text_property(game.charProps[chaa->index_id], play.charProps[chaa->index_id], property, bufer);
1085 }
Character_GetTextProperty(CharacterInfo * chaa,const char * property)1086 const char* Character_GetTextProperty(CharacterInfo *chaa, const char *property) {
1087     return get_text_property_dynamic_string(game.charProps[chaa->index_id], play.charProps[chaa->index_id], property);
1088 }
1089 
Character_SetProperty(CharacterInfo * chaa,const char * property,int value)1090 bool Character_SetProperty(CharacterInfo *chaa, const char *property, int value)
1091 {
1092     return set_int_property(play.charProps[chaa->index_id], property, value);
1093 }
1094 
Character_SetTextProperty(CharacterInfo * chaa,const char * property,const char * value)1095 bool Character_SetTextProperty(CharacterInfo *chaa, const char *property, const char *value)
1096 {
1097     return set_text_property(play.charProps[chaa->index_id], property, value);
1098 }
1099 
Character_GetActiveInventory(CharacterInfo * chaa)1100 ScriptInvItem* Character_GetActiveInventory(CharacterInfo *chaa) {
1101 
1102     if (chaa->activeinv <= 0)
1103         return NULL;
1104 
1105     return &scrInv[chaa->activeinv];
1106 }
1107 
Character_SetActiveInventory(CharacterInfo * chaa,ScriptInvItem * iit)1108 void Character_SetActiveInventory(CharacterInfo *chaa, ScriptInvItem* iit) {
1109     guis_need_update = 1;
1110 
1111     if (iit == NULL) {
1112         chaa->activeinv = -1;
1113 
1114         if (chaa->index_id == game.playercharacter) {
1115 
1116             if (GetCursorMode()==MODE_USE)
1117                 set_cursor_mode(0);
1118         }
1119         return;
1120     }
1121 
1122     if (chaa->inv[iit->id] < 1)
1123         quit("!SetActiveInventory: character doesn't have any of that inventory");
1124 
1125     chaa->activeinv = iit->id;
1126 
1127     if (chaa->index_id == game.playercharacter) {
1128         // if it's the player character, update mouse cursor
1129         update_inv_cursor(iit->id);
1130         set_cursor_mode(MODE_USE);
1131     }
1132 }
1133 
Character_GetAnimating(CharacterInfo * chaa)1134 int Character_GetAnimating(CharacterInfo *chaa) {
1135     if (chaa->animating)
1136         return 1;
1137     return 0;
1138 }
1139 
Character_GetAnimationSpeed(CharacterInfo * chaa)1140 int Character_GetAnimationSpeed(CharacterInfo *chaa) {
1141     return chaa->animspeed;
1142 }
1143 
Character_SetAnimationSpeed(CharacterInfo * chaa,int newval)1144 void Character_SetAnimationSpeed(CharacterInfo *chaa, int newval) {
1145 
1146     chaa->animspeed = newval;
1147 }
1148 
Character_GetBaseline(CharacterInfo * chaa)1149 int Character_GetBaseline(CharacterInfo *chaa) {
1150 
1151     if (chaa->baseline < 1)
1152         return 0;
1153 
1154     return chaa->baseline;
1155 }
1156 
Character_SetBaseline(CharacterInfo * chaa,int basel)1157 void Character_SetBaseline(CharacterInfo *chaa, int basel) {
1158 
1159     chaa->baseline = basel;
1160 }
1161 
Character_GetBlinkInterval(CharacterInfo * chaa)1162 int Character_GetBlinkInterval(CharacterInfo *chaa) {
1163 
1164     return chaa->blinkinterval;
1165 }
1166 
Character_SetBlinkInterval(CharacterInfo * chaa,int interval)1167 void Character_SetBlinkInterval(CharacterInfo *chaa, int interval) {
1168 
1169     if (interval < 0)
1170         quit("!SetCharacterBlinkView: invalid blink interval");
1171 
1172     chaa->blinkinterval = interval;
1173 
1174     if (chaa->blinktimer > 0)
1175         chaa->blinktimer = chaa->blinkinterval;
1176 }
1177 
Character_GetBlinkView(CharacterInfo * chaa)1178 int Character_GetBlinkView(CharacterInfo *chaa) {
1179 
1180     return chaa->blinkview + 1;
1181 }
1182 
Character_SetBlinkView(CharacterInfo * chaa,int vii)1183 void Character_SetBlinkView(CharacterInfo *chaa, int vii) {
1184 
1185     if (((vii < 2) || (vii > game.numviews)) && (vii != -1))
1186         quit("!SetCharacterBlinkView: invalid view number");
1187 
1188     chaa->blinkview = vii - 1;
1189 }
1190 
Character_GetBlinkWhileThinking(CharacterInfo * chaa)1191 int Character_GetBlinkWhileThinking(CharacterInfo *chaa) {
1192     if (chaa->flags & CHF_NOBLINKANDTHINK)
1193         return 0;
1194     return 1;
1195 }
1196 
Character_SetBlinkWhileThinking(CharacterInfo * chaa,int yesOrNo)1197 void Character_SetBlinkWhileThinking(CharacterInfo *chaa, int yesOrNo) {
1198     chaa->flags &= ~CHF_NOBLINKANDTHINK;
1199     if (yesOrNo == 0)
1200         chaa->flags |= CHF_NOBLINKANDTHINK;
1201 }
1202 
Character_GetBlockingHeight(CharacterInfo * chaa)1203 int Character_GetBlockingHeight(CharacterInfo *chaa) {
1204 
1205     return chaa->blocking_height;
1206 }
1207 
Character_SetBlockingHeight(CharacterInfo * chaa,int hit)1208 void Character_SetBlockingHeight(CharacterInfo *chaa, int hit) {
1209 
1210     chaa->blocking_height = hit;
1211 }
1212 
Character_GetBlockingWidth(CharacterInfo * chaa)1213 int Character_GetBlockingWidth(CharacterInfo *chaa) {
1214 
1215     return chaa->blocking_width;
1216 }
1217 
Character_SetBlockingWidth(CharacterInfo * chaa,int wid)1218 void Character_SetBlockingWidth(CharacterInfo *chaa, int wid) {
1219 
1220     chaa->blocking_width = wid;
1221 }
1222 
Character_GetDiagonalWalking(CharacterInfo * chaa)1223 int Character_GetDiagonalWalking(CharacterInfo *chaa) {
1224 
1225     if (chaa->flags & CHF_NODIAGONAL)
1226         return 0;
1227     return 1;
1228 }
1229 
Character_SetDiagonalWalking(CharacterInfo * chaa,int yesorno)1230 void Character_SetDiagonalWalking(CharacterInfo *chaa, int yesorno) {
1231 
1232     chaa->flags &= ~CHF_NODIAGONAL;
1233     if (!yesorno)
1234         chaa->flags |= CHF_NODIAGONAL;
1235 }
1236 
Character_GetClickable(CharacterInfo * chaa)1237 int Character_GetClickable(CharacterInfo *chaa) {
1238 
1239     if (chaa->flags & CHF_NOINTERACT)
1240         return 0;
1241     return 1;
1242 }
1243 
Character_SetClickable(CharacterInfo * chaa,int clik)1244 void Character_SetClickable(CharacterInfo *chaa, int clik) {
1245 
1246     chaa->flags &= ~CHF_NOINTERACT;
1247     // if they don't want it clickable, set the relevant bit
1248     if (clik == 0)
1249         chaa->flags |= CHF_NOINTERACT;
1250 }
1251 
Character_GetID(CharacterInfo * chaa)1252 int Character_GetID(CharacterInfo *chaa) {
1253 
1254     return chaa->index_id;
1255 
1256 }
1257 
Character_GetFrame(CharacterInfo * chaa)1258 int Character_GetFrame(CharacterInfo *chaa) {
1259     return chaa->frame;
1260 }
1261 
Character_SetFrame(CharacterInfo * chaa,int newval)1262 void Character_SetFrame(CharacterInfo *chaa, int newval) {
1263     chaa->frame = newval;
1264 }
1265 
Character_GetIdleView(CharacterInfo * chaa)1266 int Character_GetIdleView(CharacterInfo *chaa) {
1267 
1268     if (chaa->idleview < 1)
1269         return -1;
1270 
1271     return chaa->idleview + 1;
1272 }
1273 
Character_GetIInventoryQuantity(CharacterInfo * chaa,int index)1274 int Character_GetIInventoryQuantity(CharacterInfo *chaa, int index) {
1275     if ((index < 1) || (index >= game.numinvitems))
1276         quitprintf("!Character.InventoryQuantity: invalid inventory index %d", index);
1277 
1278     return chaa->inv[index];
1279 }
1280 
Character_HasInventory(CharacterInfo * chaa,ScriptInvItem * invi)1281 int Character_HasInventory(CharacterInfo *chaa, ScriptInvItem *invi)
1282 {
1283     if (invi == NULL)
1284         quit("!Character.HasInventory: NULL inventory item supplied");
1285 
1286     return (chaa->inv[invi->id] > 0) ? 1 : 0;
1287 }
1288 
Character_SetIInventoryQuantity(CharacterInfo * chaa,int index,int quant)1289 void Character_SetIInventoryQuantity(CharacterInfo *chaa, int index, int quant) {
1290     if ((index < 1) || (index >= game.numinvitems))
1291         quitprintf("!Character.InventoryQuantity: invalid inventory index %d", index);
1292 
1293     if ((quant < 0) || (quant > 32000))
1294         quitprintf("!Character.InventoryQuantity: invalid quantity %d", quant);
1295 
1296     chaa->inv[index] = quant;
1297 }
1298 
Character_GetIgnoreLighting(CharacterInfo * chaa)1299 int Character_GetIgnoreLighting(CharacterInfo *chaa) {
1300 
1301     if (chaa->flags & CHF_NOLIGHTING)
1302         return 1;
1303     return 0;
1304 }
1305 
Character_SetIgnoreLighting(CharacterInfo * chaa,int yesorno)1306 void Character_SetIgnoreLighting(CharacterInfo *chaa, int yesorno) {
1307 
1308     chaa->flags &= ~CHF_NOLIGHTING;
1309     if (yesorno)
1310         chaa->flags |= CHF_NOLIGHTING;
1311 }
1312 
Character_GetIgnoreScaling(CharacterInfo * chaa)1313 int Character_GetIgnoreScaling(CharacterInfo *chaa) {
1314 
1315     if (chaa->flags & CHF_MANUALSCALING)
1316         return 1;
1317     return 0;
1318 }
1319 
Character_SetIgnoreScaling(CharacterInfo * chaa,int yesorno)1320 void Character_SetIgnoreScaling(CharacterInfo *chaa, int yesorno) {
1321 
1322     if (yesorno) {
1323         // when setting IgnoreScaling to 1, should reset zoom level
1324         // like it used to in pre-2.71
1325         charextra[chaa->index_id].zoom = 100;
1326     }
1327     Character_SetManualScaling(chaa, yesorno);
1328 }
1329 
Character_SetManualScaling(CharacterInfo * chaa,int yesorno)1330 void Character_SetManualScaling(CharacterInfo *chaa, int yesorno) {
1331 
1332     chaa->flags &= ~CHF_MANUALSCALING;
1333     if (yesorno)
1334         chaa->flags |= CHF_MANUALSCALING;
1335 }
1336 
Character_GetIgnoreWalkbehinds(CharacterInfo * chaa)1337 int Character_GetIgnoreWalkbehinds(CharacterInfo *chaa) {
1338 
1339     if (chaa->flags & CHF_NOWALKBEHINDS)
1340         return 1;
1341     return 0;
1342 }
1343 
Character_SetIgnoreWalkbehinds(CharacterInfo * chaa,int yesorno)1344 void Character_SetIgnoreWalkbehinds(CharacterInfo *chaa, int yesorno) {
1345 
1346     chaa->flags &= ~CHF_NOWALKBEHINDS;
1347     if (yesorno)
1348         chaa->flags |= CHF_NOWALKBEHINDS;
1349 }
1350 
Character_GetMovementLinkedToAnimation(CharacterInfo * chaa)1351 int Character_GetMovementLinkedToAnimation(CharacterInfo *chaa) {
1352 
1353     if (chaa->flags & CHF_ANTIGLIDE)
1354         return 1;
1355     return 0;
1356 }
1357 
Character_SetMovementLinkedToAnimation(CharacterInfo * chaa,int yesorno)1358 void Character_SetMovementLinkedToAnimation(CharacterInfo *chaa, int yesorno) {
1359 
1360     chaa->flags &= ~CHF_ANTIGLIDE;
1361     if (yesorno)
1362         chaa->flags |= CHF_ANTIGLIDE;
1363 }
1364 
Character_GetLoop(CharacterInfo * chaa)1365 int Character_GetLoop(CharacterInfo *chaa) {
1366     return chaa->loop;
1367 }
1368 
Character_SetLoop(CharacterInfo * chaa,int newval)1369 void Character_SetLoop(CharacterInfo *chaa, int newval) {
1370     if ((newval < 0) || (newval >= views[chaa->view].numLoops))
1371         quit("!Character.Loop: invalid loop number for this view");
1372 
1373     chaa->loop = newval;
1374 
1375     if (chaa->frame >= views[chaa->view].loops[chaa->loop].numFrames)
1376         chaa->frame = 0;
1377 }
1378 
Character_GetMoving(CharacterInfo * chaa)1379 int Character_GetMoving(CharacterInfo *chaa) {
1380     if (chaa->walking)
1381         return 1;
1382     return 0;
1383 }
1384 
Character_GetDestinationX(CharacterInfo * chaa)1385 int Character_GetDestinationX(CharacterInfo *chaa) {
1386     if (chaa->walking) {
1387         MoveList *cmls = &mls[chaa->walking % TURNING_AROUND];
1388         return cmls->pos[cmls->numstage - 1] >> 16;
1389     }
1390     else
1391         return chaa->x;
1392 }
1393 
Character_GetDestinationY(CharacterInfo * chaa)1394 int Character_GetDestinationY(CharacterInfo *chaa) {
1395     if (chaa->walking) {
1396         MoveList *cmls = &mls[chaa->walking % TURNING_AROUND];
1397         return cmls->pos[cmls->numstage - 1] & 0xFFFF;
1398     }
1399     else
1400         return chaa->y;
1401 }
1402 
Character_GetName(CharacterInfo * chaa)1403 const char* Character_GetName(CharacterInfo *chaa) {
1404     return CreateNewScriptString(chaa->name);
1405 }
1406 
Character_SetName(CharacterInfo * chaa,const char * newName)1407 void Character_SetName(CharacterInfo *chaa, const char *newName) {
1408     strncpy(chaa->name, newName, 40);
1409     chaa->name[39] = 0;
1410 }
1411 
Character_GetNormalView(CharacterInfo * chaa)1412 int Character_GetNormalView(CharacterInfo *chaa) {
1413     return chaa->defview + 1;
1414 }
1415 
Character_GetPreviousRoom(CharacterInfo * chaa)1416 int Character_GetPreviousRoom(CharacterInfo *chaa) {
1417     return chaa->prevroom;
1418 }
1419 
Character_GetRoom(CharacterInfo * chaa)1420 int Character_GetRoom(CharacterInfo *chaa) {
1421     return chaa->room;
1422 }
1423 
1424 
Character_GetScaleMoveSpeed(CharacterInfo * chaa)1425 int Character_GetScaleMoveSpeed(CharacterInfo *chaa) {
1426 
1427     if (chaa->flags & CHF_SCALEMOVESPEED)
1428         return 1;
1429     return 0;
1430 }
1431 
Character_SetScaleMoveSpeed(CharacterInfo * chaa,int yesorno)1432 void Character_SetScaleMoveSpeed(CharacterInfo *chaa, int yesorno) {
1433 
1434     if ((yesorno < 0) || (yesorno > 1))
1435         quit("Character.ScaleMoveSpeed: value must be true or false (1 or 0)");
1436 
1437     chaa->flags &= ~CHF_SCALEMOVESPEED;
1438     if (yesorno)
1439         chaa->flags |= CHF_SCALEMOVESPEED;
1440 }
1441 
Character_GetScaleVolume(CharacterInfo * chaa)1442 int Character_GetScaleVolume(CharacterInfo *chaa) {
1443 
1444     if (chaa->flags & CHF_SCALEVOLUME)
1445         return 1;
1446     return 0;
1447 }
1448 
Character_SetScaleVolume(CharacterInfo * chaa,int yesorno)1449 void Character_SetScaleVolume(CharacterInfo *chaa, int yesorno) {
1450 
1451     if ((yesorno < 0) || (yesorno > 1))
1452         quit("Character.ScaleVolume: value must be true or false (1 or 0)");
1453 
1454     chaa->flags &= ~CHF_SCALEVOLUME;
1455     if (yesorno)
1456         chaa->flags |= CHF_SCALEVOLUME;
1457 }
1458 
Character_GetScaling(CharacterInfo * chaa)1459 int Character_GetScaling(CharacterInfo *chaa) {
1460     return charextra[chaa->index_id].zoom;
1461 }
1462 
Character_SetScaling(CharacterInfo * chaa,int zoomlevel)1463 void Character_SetScaling(CharacterInfo *chaa, int zoomlevel) {
1464 
1465     if ((chaa->flags & CHF_MANUALSCALING) == 0)
1466         quit("!Character.Scaling: cannot set property unless ManualScaling is enabled");
1467     if ((zoomlevel < 5) || (zoomlevel > 200))
1468         quit("!Character.Scaling: scaling level must be between 5 and 200%");
1469 
1470     charextra[chaa->index_id].zoom = zoomlevel;
1471 }
1472 
Character_GetSolid(CharacterInfo * chaa)1473 int Character_GetSolid(CharacterInfo *chaa) {
1474 
1475     if (chaa->flags & CHF_NOBLOCKING)
1476         return 0;
1477     return 1;
1478 }
1479 
Character_SetSolid(CharacterInfo * chaa,int yesorno)1480 void Character_SetSolid(CharacterInfo *chaa, int yesorno) {
1481 
1482     chaa->flags &= ~CHF_NOBLOCKING;
1483     if (!yesorno)
1484         chaa->flags |= CHF_NOBLOCKING;
1485 }
1486 
Character_GetSpeaking(CharacterInfo * chaa)1487 int Character_GetSpeaking(CharacterInfo *chaa) {
1488     if (get_character_currently_talking() == chaa->index_id)
1489         return 1;
1490 
1491     return 0;
1492 }
1493 
Character_GetSpeechColor(CharacterInfo * chaa)1494 int Character_GetSpeechColor(CharacterInfo *chaa) {
1495 
1496     return chaa->talkcolor;
1497 }
1498 
Character_SetSpeechColor(CharacterInfo * chaa,int ncol)1499 void Character_SetSpeechColor(CharacterInfo *chaa, int ncol) {
1500 
1501     chaa->talkcolor = ncol;
1502 }
1503 
Character_SetSpeechAnimationDelay(CharacterInfo * chaa,int newDelay)1504 void Character_SetSpeechAnimationDelay(CharacterInfo *chaa, int newDelay)
1505 {
1506 	if (game.options[OPT_GLOBALTALKANIMSPD] != 0)
1507         quit("!Character.SpeechAnimationDelay cannot be set when global speech animation speed is enabled");
1508 
1509     chaa->speech_anim_speed = newDelay;
1510 }
1511 
Character_GetSpeechView(CharacterInfo * chaa)1512 int Character_GetSpeechView(CharacterInfo *chaa) {
1513 
1514     return chaa->talkview + 1;
1515 }
1516 
Character_SetSpeechView(CharacterInfo * chaa,int vii)1517 void Character_SetSpeechView(CharacterInfo *chaa, int vii) {
1518     if (vii == -1) {
1519         chaa->talkview = -1;
1520         return;
1521     }
1522 
1523     if ((vii < 1) || (vii > game.numviews))
1524         quit("!SetCharacterSpeechView: invalid view number");
1525 
1526     chaa->talkview = vii - 1;
1527 }
1528 
Character_GetThinking(CharacterInfo * chaa)1529 bool Character_GetThinking(CharacterInfo *chaa)
1530 {
1531     return char_thinking == chaa->index_id;
1532 }
1533 
Character_GetThinkingFrame(CharacterInfo * chaa)1534 int Character_GetThinkingFrame(CharacterInfo *chaa)
1535 {
1536     if (char_thinking == chaa->index_id)
1537         return chaa->thinkview > 0 ? chaa->frame : -1;
1538 
1539     quit("!Character.ThinkingFrame: character is not currently thinking");
1540     return -1;
1541 }
1542 
Character_GetThinkView(CharacterInfo * chaa)1543 int Character_GetThinkView(CharacterInfo *chaa) {
1544 
1545     return chaa->thinkview + 1;
1546 }
1547 
Character_SetThinkView(CharacterInfo * chaa,int vii)1548 void Character_SetThinkView(CharacterInfo *chaa, int vii) {
1549     if (((vii < 2) || (vii > game.numviews)) && (vii != -1))
1550         quit("!SetCharacterThinkView: invalid view number");
1551 
1552     chaa->thinkview = vii - 1;
1553 }
1554 
Character_GetTransparency(CharacterInfo * chaa)1555 int Character_GetTransparency(CharacterInfo *chaa) {
1556 
1557     return GfxDef::LegacyTrans255ToTrans100(chaa->transparency);
1558 }
1559 
Character_SetTransparency(CharacterInfo * chaa,int trans)1560 void Character_SetTransparency(CharacterInfo *chaa, int trans) {
1561 
1562     if ((trans < 0) || (trans > 100))
1563         quit("!SetCharTransparent: transparency value must be between 0 and 100");
1564 
1565     chaa->transparency = GfxDef::Trans100ToLegacyTrans255(trans);
1566 }
1567 
Character_GetTurnBeforeWalking(CharacterInfo * chaa)1568 int Character_GetTurnBeforeWalking(CharacterInfo *chaa) {
1569 
1570     if (chaa->flags & CHF_NOTURNING)
1571         return 0;
1572     return 1;
1573 }
1574 
Character_SetTurnBeforeWalking(CharacterInfo * chaa,int yesorno)1575 void Character_SetTurnBeforeWalking(CharacterInfo *chaa, int yesorno) {
1576 
1577     chaa->flags &= ~CHF_NOTURNING;
1578     if (!yesorno)
1579         chaa->flags |= CHF_NOTURNING;
1580 }
1581 
Character_GetView(CharacterInfo * chaa)1582 int Character_GetView(CharacterInfo *chaa) {
1583     return chaa->view + 1;
1584 }
1585 
Character_GetWalkSpeedX(CharacterInfo * chaa)1586 int Character_GetWalkSpeedX(CharacterInfo *chaa) {
1587     return chaa->walkspeed;
1588 }
1589 
Character_GetWalkSpeedY(CharacterInfo * chaa)1590 int Character_GetWalkSpeedY(CharacterInfo *chaa) {
1591     if (chaa->walkspeed_y != UNIFORM_WALK_SPEED)
1592         return chaa->walkspeed_y;
1593 
1594     return chaa->walkspeed;
1595 }
1596 
Character_GetX(CharacterInfo * chaa)1597 int Character_GetX(CharacterInfo *chaa) {
1598     return chaa->x;
1599 }
1600 
Character_SetX(CharacterInfo * chaa,int newval)1601 void Character_SetX(CharacterInfo *chaa, int newval) {
1602     chaa->x = newval;
1603 }
1604 
Character_GetY(CharacterInfo * chaa)1605 int Character_GetY(CharacterInfo *chaa) {
1606     return chaa->y;
1607 }
1608 
Character_SetY(CharacterInfo * chaa,int newval)1609 void Character_SetY(CharacterInfo *chaa, int newval) {
1610     chaa->y = newval;
1611 }
1612 
Character_GetZ(CharacterInfo * chaa)1613 int Character_GetZ(CharacterInfo *chaa) {
1614     return chaa->z;
1615 }
1616 
Character_SetZ(CharacterInfo * chaa,int newval)1617 void Character_SetZ(CharacterInfo *chaa, int newval) {
1618     chaa->z = newval;
1619 }
1620 
1621 extern int char_speaking;
1622 
Character_GetSpeakingFrame(CharacterInfo * chaa)1623 int Character_GetSpeakingFrame(CharacterInfo *chaa) {
1624 
1625     if ((face_talking >= 0) && (facetalkrepeat))
1626     {
1627         if (facetalkchar->index_id == chaa->index_id)
1628         {
1629             return facetalkframe;
1630         }
1631     }
1632     else if (char_speaking >= 0)
1633     {
1634         if (char_speaking == chaa->index_id)
1635         {
1636             return chaa->frame;
1637         }
1638     }
1639 
1640     quit("!Character.SpeakingFrame: character is not currently speaking");
1641     return -1;
1642 }
1643 
1644 //=============================================================================
1645 
1646 // order of loops to turn character in circle from down to down
1647 int turnlooporder[8] = {0, 6, 1, 7, 3, 5, 2, 4};
1648 
walk_character(int chac,int tox,int toy,int ignwal,bool autoWalkAnims)1649 void walk_character(int chac,int tox,int toy,int ignwal, bool autoWalkAnims) {
1650     CharacterInfo*chin=&game.chars[chac];
1651     if (chin->room!=displayed_room)
1652         quit("!MoveCharacter: character not in current room");
1653 
1654     chin->flags &= ~CHF_MOVENOTWALK;
1655 
1656     int toxPassedIn = tox, toyPassedIn = toy;
1657     int charX = convert_to_low_res(chin->x);
1658     int charY = convert_to_low_res(chin->y);
1659     tox = convert_to_low_res(tox);
1660     toy = convert_to_low_res(toy);
1661 
1662     if ((tox == charX) && (toy == charY)) {
1663         StopMoving(chac);
1664         debug_script_log("%s already at destination, not moving", chin->scrname);
1665         return;
1666     }
1667 
1668     if ((chin->animating) && (autoWalkAnims))
1669         chin->animating = 0;
1670 
1671     if (chin->idleleft < 0) {
1672         ReleaseCharacterView(chac);
1673         chin->idleleft=chin->idletime;
1674     }
1675     // stop them to make sure they're on a walkable area
1676     // but save their frame first so that if they're already
1677     // moving it looks smoother
1678     int oldframe = chin->frame;
1679     int waitWas = 0, animWaitWas = 0;
1680     // if they are currently walking, save the current Wait
1681     if (chin->walking)
1682     {
1683         waitWas = chin->walkwait;
1684         animWaitWas = charextra[chac].animwait;
1685     }
1686 
1687     StopMoving (chac);
1688     chin->frame = oldframe;
1689     // use toxPassedIn cached variable so the hi-res co-ordinates
1690     // are still displayed as such
1691     debug_script_log("%s: Start move to %d,%d", chin->scrname, toxPassedIn, toyPassedIn);
1692 
1693     int move_speed_x = chin->walkspeed;
1694     int move_speed_y = chin->walkspeed;
1695 
1696     if (chin->walkspeed_y != UNIFORM_WALK_SPEED)
1697         move_speed_y = chin->walkspeed_y;
1698 
1699     if ((move_speed_x == 0) && (move_speed_y == 0)) {
1700         debug_script_warn("Warning: MoveCharacter called for '%s' with walk speed 0", chin->name);
1701     }
1702 
1703     set_route_move_speed(move_speed_x, move_speed_y);
1704     set_color_depth(8);
1705     int mslot=find_route(charX, charY, tox, toy, prepare_walkable_areas(chac), chac+CHMLSOFFS, 1, ignwal);
1706     set_color_depth(game.GetColorDepth());
1707     if (mslot>0) {
1708         chin->walking = mslot;
1709         mls[mslot].direct = ignwal;
1710 
1711         if ((game.options[OPT_NATIVECOORDINATES] != 0) &&
1712             game.IsHiRes())
1713         {
1714             convert_move_path_to_high_res(&mls[mslot]);
1715         }
1716         // cancel any pending waits on current animations
1717         // or if they were already moving, keep the current wait -
1718         // this prevents a glitch if MoveCharacter is called when they
1719         // are already moving
1720         if (autoWalkAnims)
1721         {
1722             chin->walkwait = waitWas;
1723             charextra[chac].animwait = animWaitWas;
1724 
1725             if (mls[mslot].pos[0] != mls[mslot].pos[1]) {
1726                 fix_player_sprite(&mls[mslot],chin);
1727             }
1728         }
1729         else
1730             chin->flags |= CHF_MOVENOTWALK;
1731     }
1732     else if (autoWalkAnims) // pathfinder couldn't get a route, stand them still
1733         chin->frame = 0;
1734 }
1735 
find_looporder_index(int curloop)1736 int find_looporder_index (int curloop) {
1737     int rr;
1738     for (rr = 0; rr < 8; rr++) {
1739         if (turnlooporder[rr] == curloop)
1740             return rr;
1741     }
1742     return 0;
1743 }
1744 
1745 // returns 0 to use diagonal, 1 to not
useDiagonal(CharacterInfo * char1)1746 int useDiagonal (CharacterInfo *char1) {
1747     if ((views[char1->view].numLoops < 8) || ((char1->flags & CHF_NODIAGONAL)!=0))
1748         return 1;
1749     // If they have just provided standing frames for loops 4-7, to
1750     // provide smoother turning
1751     if (views[char1->view].loops[4].numFrames < 2)
1752         return 2;
1753     return 0;
1754 }
1755 
1756 // returns 1 normally, or 0 if they only have horizontal animations
hasUpDownLoops(CharacterInfo * char1)1757 int hasUpDownLoops(CharacterInfo *char1) {
1758     // if no loops in the Down animation
1759     // or no loops in the Up animation
1760     if ((views[char1->view].loops[0].numFrames < 1) ||
1761         (views[char1->view].numLoops < 4) ||
1762         (views[char1->view].loops[3].numFrames < 1))
1763     {
1764         return 0;
1765     }
1766 
1767     return 1;
1768 }
1769 
start_character_turning(CharacterInfo * chinf,int useloop,int no_diagonal)1770 void start_character_turning (CharacterInfo *chinf, int useloop, int no_diagonal) {
1771     // work out how far round they have to turn
1772     int fromidx = find_looporder_index (chinf->loop);
1773     int toidx = find_looporder_index (useloop);
1774     //Display("Curloop: %d, needloop: %d",chinf->loop, useloop);
1775     int ii, go_anticlock = 0;
1776     // work out whether anticlockwise is quicker or not
1777     if ((toidx > fromidx) && ((toidx - fromidx) > 4))
1778         go_anticlock = 1;
1779     if ((toidx < fromidx) && ((fromidx - toidx) < 4))
1780         go_anticlock = 1;
1781     // strip any current turning_around stages
1782     chinf->walking = chinf->walking % TURNING_AROUND;
1783     if (go_anticlock)
1784         chinf->walking += TURNING_BACKWARDS;
1785     else
1786         go_anticlock = -1;
1787 
1788     // Allow the diagonal frames just for turning
1789     if (no_diagonal == 2)
1790         no_diagonal = 0;
1791 
1792     for (ii = fromidx; ii != toidx; ii -= go_anticlock) {
1793         if (ii < 0)
1794             ii = 7;
1795         if (ii >= 8)
1796             ii = 0;
1797         if (ii == toidx)
1798             break;
1799         if ((turnlooporder[ii] >= 4) && (no_diagonal > 0))
1800             continue;
1801         if (views[chinf->view].loops[turnlooporder[ii]].numFrames < 1)
1802             continue;
1803         if (turnlooporder[ii] < views[chinf->view].numLoops)
1804             chinf->walking += TURNING_AROUND;
1805     }
1806 
1807 }
1808 
fix_player_sprite(MoveList * cmls,CharacterInfo * chinf)1809 void fix_player_sprite(MoveList*cmls,CharacterInfo*chinf) {
1810     const fixed xpmove = cmls->xpermove[cmls->onstage];
1811     const fixed ypmove = cmls->ypermove[cmls->onstage];
1812 
1813     // if not moving, do nothing
1814     if ((xpmove == 0) && (ypmove == 0))
1815         return;
1816 
1817     const int useloop = GetDirectionalLoop(chinf, xpmove, ypmove);
1818 
1819     if ((game.options[OPT_ROTATECHARS] == 0) || ((chinf->flags & CHF_NOTURNING) != 0)) {
1820         chinf->loop = useloop;
1821         return;
1822     }
1823     if ((chinf->loop > kDirLoop_LastOrthogonal) && ((chinf->flags & CHF_NODIAGONAL)!=0)) {
1824         // They've just been playing an animation with an extended loop number,
1825         // so don't try and rotate using it
1826         chinf->loop = useloop;
1827         return;
1828     }
1829     if ((chinf->loop >= views[chinf->view].numLoops) ||
1830         (views[chinf->view].loops[chinf->loop].numFrames < 1) ||
1831         (hasUpDownLoops(chinf) == 0)) {
1832             // Character is not currently on a valid loop, so don't try to rotate
1833             // eg. left/right only view, but current loop 0
1834             chinf->loop = useloop;
1835             return;
1836     }
1837     const int no_diagonal = useDiagonal (chinf);
1838     start_character_turning (chinf, useloop, no_diagonal);
1839 }
1840 
1841 // Check whether two characters have walked into each other
has_hit_another_character(int sourceChar)1842 int has_hit_another_character(int sourceChar) {
1843 
1844     // if the character who's moving doesn't Bitmap *, don't bother checking
1845     if (game.chars[sourceChar].flags & CHF_NOBLOCKING)
1846         return -1;
1847 
1848     for (int ww = 0; ww < game.numcharacters; ww++) {
1849         if (game.chars[ww].on != 1) continue;
1850         if (game.chars[ww].room != displayed_room) continue;
1851         if (ww == sourceChar) continue;
1852         if (game.chars[ww].flags & CHF_NOBLOCKING) continue;
1853 
1854         if (is_char_on_another (sourceChar, ww, NULL, NULL)) {
1855             // we are now overlapping character 'ww'
1856             if ((game.chars[ww].walking) &&
1857                 ((game.chars[ww].flags & CHF_AWAITINGMOVE) == 0))
1858                 return ww;
1859         }
1860 
1861     }
1862     return -1;
1863 }
1864 
1865 // Does the next move from the character's movelist.
1866 // Returns 1 if they are now waiting for another char to move,
1867 // otherwise returns 0
doNextCharMoveStep(CharacterInfo * chi,int & char_index,CharacterExtras * chex)1868 int doNextCharMoveStep (CharacterInfo *chi, int &char_index, CharacterExtras *chex) {
1869     int ntf=0, xwas = chi->x, ywas = chi->y;
1870 
1871     if (do_movelist_move(&chi->walking,&chi->x,&chi->y) == 2)
1872     {
1873         if ((chi->flags & CHF_MOVENOTWALK) == 0)
1874             fix_player_sprite(&mls[chi->walking], chi);
1875     }
1876 
1877     ntf = has_hit_another_character(char_index);
1878     if (ntf >= 0) {
1879         chi->walkwait = 30;
1880         if (game.chars[ntf].walkspeed < 5)
1881             chi->walkwait += (5 - game.chars[ntf].walkspeed) * 5;
1882         // we are now waiting for the other char to move, so
1883         // make sure he doesn't stop for us too
1884 
1885         chi->flags |= CHF_AWAITINGMOVE;
1886 
1887         if ((chi->flags & CHF_MOVENOTWALK) == 0)
1888         {
1889             chi->frame = 0;
1890             chex->animwait = chi->walkwait;
1891         }
1892 
1893         if ((chi->walking < 1) || (chi->walking >= TURNING_AROUND)) ;
1894         else if (mls[chi->walking].onpart > 0) {
1895             mls[chi->walking].onpart --;
1896             chi->x = xwas;
1897             chi->y = ywas;
1898         }
1899         debug_script_log("%s: Bumped into %s, waiting for them to move", chi->scrname, game.chars[ntf].scrname);
1900         return 1;
1901     }
1902     return 0;
1903 }
1904 
find_nearest_walkable_area_within(int * xx,int * yy,int range,int step)1905 int find_nearest_walkable_area_within(int *xx, int *yy, int range, int step)
1906 {
1907     int ex, ey, nearest = 99999, thisis, nearx = 0, neary = 0;
1908     int startx = 0, starty = 14;
1909     int roomWidthLowRes = convert_to_low_res(thisroom.width);
1910     int roomHeightLowRes = convert_to_low_res(thisroom.height);
1911     int xwidth = roomWidthLowRes, yheight = roomHeightLowRes;
1912 
1913     int xLowRes = convert_to_low_res(xx[0]);
1914     int yLowRes = convert_to_low_res(yy[0]);
1915     int rightEdge = convert_to_low_res(thisroom.right);
1916     int leftEdge = convert_to_low_res(thisroom.left);
1917     int topEdge = convert_to_low_res(thisroom.top);
1918     int bottomEdge = convert_to_low_res(thisroom.bottom);
1919 
1920     // tweak because people forget to move the edges sometimes
1921     // if the player is already over the edge, ignore it
1922     if (xLowRes >= rightEdge) rightEdge = roomWidthLowRes;
1923     if (xLowRes <= leftEdge) leftEdge = 0;
1924     if (yLowRes >= bottomEdge) bottomEdge = roomHeightLowRes;
1925     if (yLowRes <= topEdge) topEdge = 0;
1926 
1927     if (range > 0)
1928     {
1929         startx = xLowRes - range;
1930         starty = yLowRes - range;
1931         xwidth = startx + range * 2;
1932         yheight = starty + range * 2;
1933         if (startx < 0) startx = 0;
1934         if (starty < 10) starty = 10;
1935         if (xwidth > roomWidthLowRes) xwidth = roomWidthLowRes;
1936         if (yheight > roomHeightLowRes) yheight = roomHeightLowRes;
1937     }
1938 
1939     for (ex = startx; ex < xwidth; ex += step) {
1940         for (ey = starty; ey < yheight; ey += step) {
1941             // non-walkalbe, so don't go here
1942             if (thisroom.walls->GetPixel(ex,ey) == 0) continue;
1943             // off a screen edge, don't move them there
1944             if ((ex <= leftEdge) || (ex >= rightEdge) ||
1945                 (ey <= topEdge) || (ey >= bottomEdge))
1946                 continue;
1947             // otherwise, calculate distance from target
1948             thisis=(int) ::sqrt((double)((ex - xLowRes) * (ex - xLowRes) + (ey - yLowRes) * (ey - yLowRes)));
1949             if (thisis<nearest) { nearest=thisis; nearx=ex; neary=ey; }
1950         }
1951     }
1952     if (nearest < 90000)
1953     {
1954         xx[0] = convert_back_to_high_res(nearx);
1955         yy[0] = convert_back_to_high_res(neary);
1956         return 1;
1957     }
1958 
1959     return 0;
1960 }
1961 
find_nearest_walkable_area(int * xx,int * yy)1962 void find_nearest_walkable_area (int *xx, int *yy) {
1963 
1964 
1965     int pixValue = thisroom.walls->GetPixel(convert_to_low_res(xx[0]), convert_to_low_res(yy[0]));
1966     // only fix this code if the game was built with 2.61 or above
1967     if (pixValue == 0 || (loaded_game_file_version >= kGameVersion_261 && pixValue < 1))
1968     {
1969         // First, check every 2 pixels within immediate area
1970         if (!find_nearest_walkable_area_within(xx, yy, 20, 2))
1971         {
1972             // If not, check whole screen at 5 pixel intervals
1973             find_nearest_walkable_area_within(xx, yy, -1, 5);
1974         }
1975     }
1976 
1977 }
1978 
FindReasonableLoopForCharacter(CharacterInfo * chap)1979 void FindReasonableLoopForCharacter(CharacterInfo *chap) {
1980 
1981     if (chap->loop >= views[chap->view].numLoops)
1982         chap->loop=kDirLoop_Default;
1983     if (views[chap->view].numLoops < 1)
1984         quitprintf("!View %d does not have any loops", chap->view + 1);
1985 
1986     // if the current loop has no frames, find one that does
1987     if (views[chap->view].loops[chap->loop].numFrames < 1)
1988     {
1989         for (int i = 0; i < views[chap->view].numLoops; i++)
1990         {
1991             if (views[chap->view].loops[i].numFrames > 0) {
1992                 chap->loop = i;
1993                 break;
1994             }
1995         }
1996     }
1997 
1998 }
1999 
walk_or_move_character(CharacterInfo * chaa,int x,int y,int blocking,int direct,bool isWalk)2000 void walk_or_move_character(CharacterInfo *chaa, int x, int y, int blocking, int direct, bool isWalk)
2001 {
2002     if (chaa->on != 1)
2003         quit("!MoveCharacterBlocking: character is turned off and cannot be moved");
2004 
2005     if ((direct == ANYWHERE) || (direct == 1))
2006         walk_character(chaa->index_id, x, y, 1, isWalk);
2007     else if ((direct == WALKABLE_AREAS) || (direct == 0))
2008         walk_character(chaa->index_id, x, y, 0, isWalk);
2009     else
2010         quit("!Character.Walk: Direct must be ANYWHERE or WALKABLE_AREAS");
2011 
2012     if ((blocking == BLOCKING) || (blocking == 1))
2013         GameLoopUntilEvent(UNTIL_MOVEEND,(long)&chaa->walking);
2014     else if ((blocking != IN_BACKGROUND) && (blocking != 0))
2015         quit("!Character.Walk: Blocking must be BLOCKING or IN_BACKGRUOND");
2016 
2017 }
2018 
is_valid_character(int newchar)2019 int is_valid_character(int newchar) {
2020     if ((newchar < 0) || (newchar >= game.numcharacters)) return 0;
2021     return 1;
2022 }
2023 
wantMoveNow(CharacterInfo * chi,CharacterExtras * chex)2024 int wantMoveNow (CharacterInfo *chi, CharacterExtras *chex) {
2025     // check most likely case first
2026     if ((chex->zoom == 100) || ((chi->flags & CHF_SCALEMOVESPEED) == 0))
2027         return 1;
2028 
2029     // the % checks don't work when the counter is negative, so once
2030     // it wraps round, correct it
2031     while (chi->walkwaitcounter < 0) {
2032         chi->walkwaitcounter += 12000;
2033     }
2034 
2035     // scaling 170-200%, move 175% speed
2036     if (chex->zoom >= 170) {
2037         if ((chi->walkwaitcounter % 4) >= 1)
2038             return 2;
2039         else
2040             return 1;
2041     }
2042     // scaling 140-170%, move 150% speed
2043     else if (chex->zoom >= 140) {
2044         if ((chi->walkwaitcounter % 2) == 1)
2045             return 2;
2046         else
2047             return 1;
2048     }
2049     // scaling 115-140%, move 125% speed
2050     else if (chex->zoom >= 115) {
2051         if ((chi->walkwaitcounter % 4) >= 3)
2052             return 2;
2053         else
2054             return 1;
2055     }
2056     // scaling 80-120%, normal speed
2057     else if (chex->zoom >= 80)
2058         return 1;
2059     // scaling 60-80%, move 75% speed
2060     if (chex->zoom >= 60) {
2061         if ((chi->walkwaitcounter % 4) >= 1)
2062             return -1;
2063         else if (chex->xwas != INVALID_X) {
2064             // move the second half of the movement to make it smoother
2065             chi->x = chex->xwas;
2066             chi->y = chex->ywas;
2067             chex->xwas = INVALID_X;
2068         }
2069     }
2070     // scaling 30-60%, move 50% speed
2071     else if (chex->zoom >= 30) {
2072         if ((chi->walkwaitcounter % 2) == 1)
2073             return -1;
2074         else if (chex->xwas != INVALID_X) {
2075             // move the second half of the movement to make it smoother
2076             chi->x = chex->xwas;
2077             chi->y = chex->ywas;
2078             chex->xwas = INVALID_X;
2079         }
2080     }
2081     // scaling 0-30%, move 25% speed
2082     else {
2083         if ((chi->walkwaitcounter % 4) >= 3)
2084             return -1;
2085         if (((chi->walkwaitcounter % 4) == 1) && (chex->xwas != INVALID_X)) {
2086             // move the second half of the movement to make it smoother
2087             chi->x = chex->xwas;
2088             chi->y = chex->ywas;
2089             chex->xwas = INVALID_X;
2090         }
2091 
2092     }
2093 
2094     return 0;
2095 }
2096 
setup_player_character(int charid)2097 void setup_player_character(int charid) {
2098     game.playercharacter = charid;
2099     playerchar = &game.chars[charid];
2100     _sc_PlayerCharPtr = ccGetObjectHandleFromAddress((char*)playerchar);
2101     if (loaded_game_file_version < kGameVersion_270) {
2102         ccAddExternalDynamicObject("player", playerchar, &ccDynamicCharacter);
2103     }
2104 }
2105 
animate_character(CharacterInfo * chap,int loopn,int sppd,int rept,int noidleoverride,int direction)2106 void animate_character(CharacterInfo *chap, int loopn,int sppd,int rept, int noidleoverride, int direction) {
2107 
2108     if ((chap->view < 0) || (chap->view > game.numviews)) {
2109         quitprintf("!AnimateCharacter: you need to set the view number first\n"
2110             "(trying to animate '%s' using loop %d. View is currently %d).",chap->name,loopn,chap->view+1);
2111     }
2112     debug_script_log("%s: Start anim view %d loop %d, spd %d, repeat %d", chap->scrname, chap->view+1, loopn, sppd, rept);
2113     if ((chap->idleleft < 0) && (noidleoverride == 0)) {
2114         // if idle view in progress for the character (and this is not the
2115         // "start idle animation" animate_character call), stop the idle anim
2116         Character_UnlockView(chap);
2117         chap->idleleft=chap->idletime;
2118     }
2119     if ((loopn < 0) || (loopn >= views[chap->view].numLoops))
2120         quit("!AnimateCharacter: invalid loop number specified");
2121     Character_StopMoving(chap);
2122     chap->animating=1;
2123     if (rept) chap->animating |= CHANIM_REPEAT;
2124     if (direction) chap->animating |= CHANIM_BACKWARDS;
2125 
2126     chap->animating|=((sppd << 8) & 0xff00);
2127     chap->loop=loopn;
2128 
2129     if (direction) {
2130         chap->frame = views[chap->view].loops[loopn].numFrames - 1;
2131     }
2132     else
2133         chap->frame=0;
2134 
2135     chap->wait = sppd + views[chap->view].loops[loopn].frames[chap->frame].speed;
2136     CheckViewFrameForCharacter(chap);
2137 }
2138 
CheckViewFrameForCharacter(CharacterInfo * chi)2139 void CheckViewFrameForCharacter(CharacterInfo *chi) {
2140 
2141     int soundVolume = SCR_NO_VALUE;
2142 
2143     if (chi->flags & CHF_SCALEVOLUME) {
2144         // adjust the sound volume using the character's zoom level
2145         int zoom_level = charextra[chi->index_id].zoom;
2146         if (zoom_level == 0)
2147             zoom_level = 100;
2148 
2149         soundVolume = zoom_level;
2150 
2151         if (soundVolume < 0)
2152             soundVolume = 0;
2153         if (soundVolume > 100)
2154             soundVolume = 100;
2155     }
2156 
2157     CheckViewFrame(chi->view, chi->loop, chi->frame, soundVolume);
2158 }
2159 
GetCharacterImage(int charid,int * isFlipped)2160 Bitmap *GetCharacterImage(int charid, int *isFlipped)
2161 {
2162     if (!gfxDriver->HasAcceleratedStretchAndFlip())
2163     {
2164         if (actsps[charid + MAX_INIT_SPR] != NULL)
2165         {
2166             // the actsps image is pre-flipped, so no longer register the image as such
2167             if (isFlipped)
2168                 *isFlipped = 0;
2169             return actsps[charid + MAX_INIT_SPR];
2170         }
2171     }
2172     CharacterInfo*chin=&game.chars[charid];
2173     int sppic = views[chin->view].loops[chin->loop].frames[chin->frame].pic;
2174     return spriteset[sppic];
2175 }
2176 
GetCharacterAtLocation(int xx,int yy)2177 CharacterInfo *GetCharacterAtLocation(int xx, int yy) {
2178     int hsnum = GetCharacterAt(xx, yy);
2179     if (hsnum < 0)
2180         return NULL;
2181     return &game.chars[hsnum];
2182 }
2183 
2184 extern int char_lowest_yp, obj_lowest_yp;
2185 
is_pos_on_character(int xx,int yy)2186 int is_pos_on_character(int xx,int yy) {
2187     int cc,sppic,lowestyp=0,lowestwas=-1;
2188     for (cc=0;cc<game.numcharacters;cc++) {
2189         if (game.chars[cc].room!=displayed_room) continue;
2190         if (game.chars[cc].on==0) continue;
2191         if (game.chars[cc].flags & CHF_NOINTERACT) continue;
2192         if (game.chars[cc].view < 0) continue;
2193         CharacterInfo*chin=&game.chars[cc];
2194 
2195         if ((chin->view < 0) ||
2196             (chin->loop >= views[chin->view].numLoops) ||
2197             (chin->frame >= views[chin->view].loops[chin->loop].numFrames))
2198         {
2199             continue;
2200         }
2201 
2202         sppic=views[chin->view].loops[chin->loop].frames[chin->frame].pic;
2203         int usewid = charextra[cc].width;
2204         int usehit = charextra[cc].height;
2205         if (usewid==0) usewid=spritewidth[sppic];
2206         if (usehit==0) usehit=spriteheight[sppic];
2207         int xxx = chin->x - divide_down_coordinate(usewid) / 2;
2208         int yyy = chin->get_effective_y() - divide_down_coordinate(usehit);
2209 
2210         int mirrored = views[chin->view].loops[chin->loop].frames[chin->frame].flags & VFLG_FLIPSPRITE;
2211         Bitmap *theImage = GetCharacterImage(cc, &mirrored);
2212 
2213         if (is_pos_in_sprite(xx,yy,xxx,yyy, theImage,
2214             divide_down_coordinate(usewid),
2215             divide_down_coordinate(usehit), mirrored) == FALSE)
2216             continue;
2217 
2218         int use_base = chin->get_baseline();
2219         if (use_base < lowestyp) continue;
2220         lowestyp=use_base;
2221         lowestwas=cc;
2222     }
2223     char_lowest_yp = lowestyp;
2224     return lowestwas;
2225 }
2226 
get_char_blocking_rect(int charid,int * x1,int * y1,int * width,int * y2)2227 void get_char_blocking_rect(int charid, int *x1, int *y1, int *width, int *y2) {
2228     CharacterInfo *char1 = &game.chars[charid];
2229     int cwidth, fromx;
2230 
2231     if (char1->blocking_width < 1)
2232         cwidth = divide_down_coordinate(GetCharacterWidth(charid)) - 4;
2233     else
2234         cwidth = char1->blocking_width;
2235 
2236     fromx = char1->x - cwidth/2;
2237     if (fromx < 0) {
2238         cwidth += fromx;
2239         fromx = 0;
2240     }
2241     if (fromx + cwidth >= convert_back_to_high_res(walkable_areas_temp->GetWidth()))
2242         cwidth = convert_back_to_high_res(walkable_areas_temp->GetWidth()) - fromx;
2243 
2244     if (x1)
2245         *x1 = fromx;
2246     if (width)
2247         *width = cwidth;
2248     if (y1)
2249         *y1 = char1->get_blocking_top();
2250     if (y2)
2251         *y2 = char1->get_blocking_bottom();
2252 }
2253 
2254 // Check whether the source char has walked onto character ww
is_char_on_another(int sourceChar,int ww,int * fromxptr,int * cwidptr)2255 int is_char_on_another (int sourceChar, int ww, int*fromxptr, int*cwidptr) {
2256 
2257     int fromx, cwidth;
2258     int y1, y2;
2259     get_char_blocking_rect(ww, &fromx, &y1, &cwidth, &y2);
2260 
2261     if (fromxptr)
2262         fromxptr[0] = fromx;
2263     if (cwidptr)
2264         cwidptr[0] = cwidth;
2265 
2266     // if the character trying to move is already on top of
2267     // this char somehow, allow them through
2268     if ((sourceChar >= 0) &&
2269         // x/width are left and width co-ords, so they need >= and <
2270         (game.chars[sourceChar].x >= fromx) &&
2271         (game.chars[sourceChar].x < fromx + cwidth) &&
2272         // y1/y2 are the top/bottom co-ords, so they need >= / <=
2273         (game.chars[sourceChar].y >= y1 ) &&
2274         (game.chars[sourceChar].y <= y2 ))
2275         return 1;
2276 
2277     return 0;
2278 }
2279 
my_getpixel(Bitmap * blk,int x,int y)2280 int my_getpixel(Bitmap *blk, int x, int y) {
2281     if ((x < 0) || (y < 0) || (x >= blk->GetWidth()) || (y >= blk->GetHeight()))
2282         return -1;
2283 
2284     // strip the alpha channel
2285 	// TODO: is there a way to do this vtable thing with Bitmap?
2286 	BITMAP *al_bmp = (BITMAP*)blk->GetAllegroBitmap();
2287     return al_bmp->vtable->getpixel(al_bmp, x, y) & 0x00ffffff;
2288 }
2289 
check_click_on_character(int xx,int yy,int mood)2290 int check_click_on_character(int xx,int yy,int mood) {
2291     int lowestwas=is_pos_on_character(xx,yy);
2292     if (lowestwas>=0) {
2293         RunCharacterInteraction (lowestwas, mood);
2294         return 1;
2295     }
2296     return 0;
2297 }
2298 
_DisplaySpeechCore(int chid,const char * displbuf)2299 void _DisplaySpeechCore(int chid, const char *displbuf) {
2300     if (displbuf[0] == 0) {
2301         // no text, just update the current character who's speaking
2302         // this allows the portrait side to be switched with an empty
2303         // speech line
2304         play.swap_portrait_lastchar = chid;
2305         return;
2306     }
2307 
2308     // adjust timing of text (so that DisplaySpeech("%s", str) pauses
2309     // for the length of the string not 2 frames)
2310     int len = (int)strlen(displbuf);
2311     if (len > source_text_length + 3)
2312         source_text_length = len;
2313 
2314     DisplaySpeech(displbuf, chid);
2315 }
2316 
_DisplayThoughtCore(int chid,const char * displbuf)2317 void _DisplayThoughtCore(int chid, const char *displbuf) {
2318     // adjust timing of text (so that DisplayThought("%s", str) pauses
2319     // for the length of the string not 2 frames)
2320     int len = (int)strlen(displbuf);
2321     if (len > source_text_length + 3)
2322         source_text_length = len;
2323 
2324     int xpp = -1, ypp = -1, width = -1;
2325 
2326     if ((game.options[OPT_SPEECHTYPE] == 0) || (game.chars[chid].thinkview <= 0)) {
2327         // lucasarts-style, so we want a speech bubble actually above
2328         // their head (or if they have no think anim in Sierra-style)
2329         width = multiply_up_coordinate(play.speech_bubble_width);
2330         xpp = (multiply_up_coordinate(game.chars[chid].x) - offsetx) - width / 2;
2331         if (xpp < 0)
2332             xpp = 0;
2333         // -1 will automatically put it above the char's head
2334         ypp = -1;
2335     }
2336 
2337     _displayspeech ((char*)displbuf, chid, xpp, ypp, width, 1);
2338 }
2339 
_displayspeech(const char * texx,int aschar,int xx,int yy,int widd,int isThought)2340 void _displayspeech(const char*texx, int aschar, int xx, int yy, int widd, int isThought) {
2341     if (!is_valid_character(aschar))
2342         quit("!DisplaySpeech: invalid character");
2343 
2344     CharacterInfo *speakingChar = &game.chars[aschar];
2345     if ((speakingChar->view < 0) || (speakingChar->view >= game.numviews))
2346         quit("!DisplaySpeech: character has invalid view");
2347 
2348     if (is_text_overlay > 0)
2349         quit("!DisplaySpeech: speech was already displayed (nested DisplaySpeech, perhaps room script and global script conflict?)");
2350 
2351     EndSkippingUntilCharStops();
2352 
2353     said_speech_line = 1;
2354 
2355     int aa;
2356     if (play.bgspeech_stay_on_display == 0) {
2357         // remove any background speech
2358         for (aa=0;aa<numscreenover;aa++) {
2359             if (screenover[aa].timeout > 0) {
2360                 remove_screen_overlay(screenover[aa].type);
2361                 aa--;
2362             }
2363         }
2364     }
2365     said_text = 1;
2366 
2367     // the strings are pre-translated
2368     //texx = get_translation(texx);
2369     our_eip=150;
2370 
2371     int isPause = 1;
2372     // if the message is all .'s, don't display anything
2373     for (aa = 0; texx[aa] != 0; aa++) {
2374         if (texx[aa] != '.') {
2375             isPause = 0;
2376             break;
2377         }
2378     }
2379 
2380     play.messagetime = GetTextDisplayTime(texx);
2381     play.speech_in_post_state = false;
2382 
2383     if (isPause) {
2384         if (update_music_at > 0)
2385             update_music_at += play.messagetime;
2386         GameLoopUntilEvent(UNTIL_INTISNEG,(long)&play.messagetime);
2387         return;
2388     }
2389 
2390     int textcol = speakingChar->talkcolor;
2391 
2392     // if it's 0, it won't be recognised as speech
2393     if (textcol == 0)
2394         textcol = 16;
2395 
2396     int allowShrink = 0;
2397     int bwidth = widd;
2398     if (bwidth < 0)
2399         bwidth = play.viewport.GetWidth()/2 + play.viewport.GetWidth()/4;
2400 
2401     our_eip=151;
2402 
2403     int useview = speakingChar->talkview;
2404     if (isThought) {
2405         useview = speakingChar->thinkview;
2406         // view 0 is not valid for think views
2407         if (useview == 0)
2408             useview = -1;
2409         // speech bubble can shrink to fit
2410         allowShrink = 1;
2411         if (speakingChar->room != displayed_room) {
2412             // not in room, centre it
2413             xx = -1;
2414             yy = -1;
2415         }
2416     }
2417 
2418     if (useview >= game.numviews)
2419         quitprintf("!Character.Say: attempted to use view %d for animation, but it does not exist", useview + 1);
2420 
2421     int tdxp = xx,tdyp = yy;
2422     int oldview=-1, oldloop = -1;
2423     int ovr_type = 0;
2424 
2425     text_lips_offset = 0;
2426     text_lips_text = texx;
2427 
2428     Bitmap *closeupface=NULL;
2429     if (texx[0]=='&') {
2430         // auto-speech
2431         int igr=atoi(&texx[1]);
2432         while ((texx[0]!=' ') & (texx[0]!=0)) texx++;
2433         if (texx[0]==' ') texx++;
2434         if (igr <= 0)
2435             quit("DisplaySpeech: auto-voice symbol '&' not followed by valid integer");
2436 
2437         text_lips_text = texx;
2438 
2439         if (play_speech(aschar,igr)) {
2440             if (play.want_speech == 2)
2441                 texx = "  ";  // speech only, no text.
2442         }
2443     }
2444     if (game.options[OPT_SPEECHTYPE] == 3)
2445         remove_screen_overlay(OVER_COMPLETE);
2446     our_eip=1500;
2447 
2448     if (game.options[OPT_SPEECHTYPE] == 0)
2449         allowShrink = 1;
2450 
2451     if (speakingChar->idleleft < 0)  {
2452         // if idle anim in progress for the character, stop it
2453         ReleaseCharacterView(aschar);
2454         //    speakingChar->idleleft = speakingChar->idletime;
2455     }
2456 
2457     bool overlayPositionFixed = false;
2458     int charFrameWas = 0;
2459     int viewWasLocked = 0;
2460     if (speakingChar->flags & CHF_FIXVIEW)
2461         viewWasLocked = 1;
2462 
2463     /*if ((speakingChar->room == displayed_room) ||
2464     ((useview >= 0) && (game.options[OPT_SPEECHTYPE] > 0)) ) {*/
2465 
2466     if (speakingChar->room == displayed_room) {
2467         // If the character is in this room, go for it - otherwise
2468         // run the "else" clause which  does text in the middle of
2469         // the screen.
2470         our_eip=1501;
2471         if (tdxp < 0)
2472             tdxp = multiply_up_coordinate(speakingChar->x) - offsetx;
2473         if (tdxp < 2)
2474             tdxp=2;
2475 
2476         if (speakingChar->walking)
2477             StopMoving(aschar);
2478 
2479         // save the frame we need to go back to
2480         // if they were moving, this will be 0 (because we just called
2481         // StopMoving); otherwise, it might be a specific animation
2482         // frame which we should return to
2483         if (viewWasLocked)
2484             charFrameWas = speakingChar->frame;
2485 
2486         // if the current loop doesn't exist in talking view, use loop 0
2487         if (speakingChar->loop >= views[speakingChar->view].numLoops)
2488             speakingChar->loop = 0;
2489 
2490         if ((speakingChar->view < 0) ||
2491             (speakingChar->loop >= views[speakingChar->view].numLoops) ||
2492             (views[speakingChar->view].loops[speakingChar->loop].numFrames < 1))
2493         {
2494             quitprintf("Unable to display speech because the character %s has an invalid view frame (View %d, loop %d, frame %d)", speakingChar->scrname, speakingChar->view + 1, speakingChar->loop, speakingChar->frame);
2495         }
2496 
2497         our_eip=1504;
2498 
2499         if (tdyp < 0)
2500         {
2501             int sppic = views[speakingChar->view].loops[speakingChar->loop].frames[0].pic;
2502             tdyp = multiply_up_coordinate(speakingChar->get_effective_y()) - offsety - get_fixed_pixel_size(5);
2503             if (charextra[aschar].height < 1)
2504                 tdyp -= spriteheight[sppic];
2505             else
2506                 tdyp -= charextra[aschar].height;
2507             // if it's a thought, lift it a bit further up
2508             if (isThought)
2509                 tdyp -= get_fixed_pixel_size(10);
2510         }
2511 
2512         our_eip=1505;
2513         if (tdyp < 5)
2514             tdyp=5;
2515 
2516         tdxp=-tdxp;  // tell it to centre it
2517         our_eip=152;
2518 
2519         if ((useview >= 0) && (game.options[OPT_SPEECHTYPE] > 0)) {
2520             // Sierra-style close-up portrait
2521 
2522             if (play.swap_portrait_lastchar != aschar) {
2523                 // if the portraits are set to Alternate, OR they are
2524                 // set to Left but swap_portrait has been set to 1 (the old
2525                 // method for enabling it), then swap them round
2526                 if ((game.options[OPT_PORTRAITSIDE] == PORTRAIT_ALTERNATE) ||
2527                     ((game.options[OPT_PORTRAITSIDE] == 0) &&
2528                     (play.swap_portrait_side > 0))) {
2529 
2530                         if (play.swap_portrait_side == 2)
2531                             play.swap_portrait_side = 1;
2532                         else
2533                             play.swap_portrait_side = 2;
2534                 }
2535 
2536                 if (game.options[OPT_PORTRAITSIDE] == PORTRAIT_XPOSITION) {
2537                     // Portrait side based on character X-positions
2538                     if (play.swap_portrait_lastchar < 0) {
2539                         // No previous character been spoken to
2540                         // therefore, assume it's the player
2541                         if(game.playercharacter != aschar && game.chars[game.playercharacter].room == speakingChar->room && game.chars[game.playercharacter].on == 1)
2542                             play.swap_portrait_lastchar = game.playercharacter;
2543                         else
2544                             // The player's not here. Find another character in this room
2545                             // that it could be
2546                             for (int ce = 0; ce < game.numcharacters; ce++) {
2547                                 if ((game.chars[ce].room == speakingChar->room) &&
2548                                     (game.chars[ce].on == 1) &&
2549                                     (ce != aschar)) {
2550                                         play.swap_portrait_lastchar = ce;
2551                                         break;
2552                                 }
2553                             }
2554                     }
2555 
2556                     if (play.swap_portrait_lastchar >= 0) {
2557                         // if this character is right of the one before, put the
2558                         // portrait on the right
2559                         if (speakingChar->x > game.chars[play.swap_portrait_lastchar].x)
2560                             play.swap_portrait_side = -1;
2561                         else
2562                             play.swap_portrait_side = 0;
2563                     }
2564                 }
2565                 play.swap_portrait_lastlastchar = play.swap_portrait_lastchar;
2566                 play.swap_portrait_lastchar = aschar;
2567             }
2568             else
2569                 // If the portrait side is based on the character's X position and the same character is
2570                 // speaking, compare against the previous *previous* character to see where the speech should be
2571                 if (game.options[OPT_PORTRAITSIDE] == PORTRAIT_XPOSITION && play.swap_portrait_lastlastchar >= 0) {
2572                     if (speakingChar->x > game.chars[play.swap_portrait_lastlastchar].x)
2573                         play.swap_portrait_side = -1;
2574                     else
2575                         play.swap_portrait_side = 0;
2576                 }
2577 
2578             // Determine whether to display the portrait on the left or right
2579             int portrait_on_right = 0;
2580 
2581             if (game.options[OPT_SPEECHTYPE] == 3)
2582             { }  // always on left with QFG-style speech
2583             else if ((play.swap_portrait_side == 1) ||
2584                 (play.swap_portrait_side == -1) ||
2585                 (game.options[OPT_PORTRAITSIDE] == PORTRAIT_RIGHT))
2586                 portrait_on_right = 1;
2587 
2588 
2589             int bigx=0,bigy=0,kk;
2590             ViewStruct*viptr=&views[useview];
2591             for (kk = 0; kk < viptr->loops[0].numFrames; kk++)
2592             {
2593                 int tw = spritewidth[viptr->loops[0].frames[kk].pic];
2594                 if (tw > bigx) bigx=tw;
2595                 tw = spriteheight[viptr->loops[0].frames[kk].pic];
2596                 if (tw > bigy) bigy=tw;
2597             }
2598 
2599             // if they accidentally used a large full-screen image as the sierra-style
2600             // talk view, correct it
2601             if ((game.options[OPT_SPEECHTYPE] != 3) && (bigx > play.viewport.GetWidth() - get_fixed_pixel_size(50)))
2602                 bigx = play.viewport.GetWidth() - get_fixed_pixel_size(50);
2603 
2604             if (widd > 0)
2605                 bwidth = widd - bigx;
2606 
2607             our_eip=153;
2608             int ovr_yp = get_fixed_pixel_size(20);
2609             int view_frame_x = 0;
2610             int view_frame_y = 0;
2611             facetalk_qfg4_override_placement_x = false;
2612             facetalk_qfg4_override_placement_y = false;
2613 
2614             if (game.options[OPT_SPEECHTYPE] == 3) {
2615                 // QFG4-style whole screen picture
2616                 closeupface = BitmapHelper::CreateBitmap(play.viewport.GetWidth(), play.viewport.GetHeight(), spriteset[viptr->loops[0].frames[0].pic]->GetColorDepth());
2617                 closeupface->Clear(0);
2618                 if (xx < 0 && play.speech_portrait_placement)
2619                 {
2620                     facetalk_qfg4_override_placement_x = true;
2621                     view_frame_x = play.speech_portrait_x;
2622                 }
2623                 if (yy < 0 && play.speech_portrait_placement)
2624                 {
2625                     facetalk_qfg4_override_placement_y = true;
2626                     view_frame_y = play.speech_portrait_y;
2627                 }
2628                 else
2629                 {
2630                     view_frame_y = play.viewport.GetHeight()/2 - spriteheight[viptr->loops[0].frames[0].pic]/2;
2631                 }
2632                 bigx = play.viewport.GetWidth()/2 - get_fixed_pixel_size(20);
2633                 ovr_type = OVER_COMPLETE;
2634                 ovr_yp = 0;
2635                 tdyp = -1;  // center vertically
2636             }
2637             else {
2638                 // KQ6-style close-up face picture
2639                 if (yy < 0 && play.speech_portrait_placement)
2640                 {
2641                     ovr_yp = play.speech_portrait_y;
2642                 }
2643                 else if (yy < 0)
2644                     ovr_yp = adjust_y_for_guis (ovr_yp);
2645                 else
2646                     ovr_yp = yy;
2647 
2648                 closeupface = BitmapHelper::CreateTransparentBitmap(bigx+1,bigy+1,spriteset[viptr->loops[0].frames[0].pic]->GetColorDepth());
2649                 ovr_type = OVER_PICTURE;
2650 
2651                 if (yy < 0)
2652                     tdyp = ovr_yp + get_textwindow_top_border_height(play.speech_textwindow_gui);
2653             }
2654             const ViewFrame *vf = &viptr->loops[0].frames[0];
2655             const bool closeupface_has_alpha = (game.spriteflags[vf->pic] & SPF_ALPHACHANNEL) != 0;
2656             DrawViewFrame(closeupface, vf, view_frame_x, view_frame_y);
2657 
2658             int overlay_x = get_fixed_pixel_size(10);
2659             if (xx < 0) {
2660                 tdxp = bigx + get_textwindow_border_width(play.speech_textwindow_gui) / 2;
2661                 if (play.speech_portrait_placement)
2662                 {
2663                     overlay_x = play.speech_portrait_x;
2664                     tdxp += overlay_x + get_fixed_pixel_size(6);
2665                 }
2666                 else
2667                 {
2668                     tdxp += get_fixed_pixel_size(16);
2669                 }
2670 
2671                 int maxWidth = (play.viewport.GetWidth() - tdxp) - get_fixed_pixel_size(5) -
2672                     get_textwindow_border_width (play.speech_textwindow_gui) / 2;
2673 
2674                 if (bwidth > maxWidth)
2675                     bwidth = maxWidth;
2676             }
2677             else {
2678                 tdxp = xx + bigx + get_fixed_pixel_size(8);
2679                 overlay_x = xx;
2680             }
2681 
2682             // allow the text box to be shrunk to fit the text
2683             allowShrink = 1;
2684 
2685             // if the portrait's on the right, swap it round
2686             if (portrait_on_right) {
2687                 if ((xx < 0) || (widd < 0)) {
2688                     tdxp = get_fixed_pixel_size(9);
2689                     if (play.speech_portrait_placement)
2690                     {
2691                         overlay_x = (play.viewport.GetWidth() - bigx) - play.speech_portrait_x;
2692                         int maxWidth = overlay_x - tdxp - get_fixed_pixel_size(9) -
2693                             get_textwindow_border_width (play.speech_textwindow_gui) / 2;
2694                         if (bwidth > maxWidth)
2695                             bwidth = maxWidth;
2696                     }
2697                     else
2698                     {
2699                         overlay_x = (play.viewport.GetWidth() - bigx) - get_fixed_pixel_size(5);
2700                     }
2701                 }
2702                 else {
2703                     overlay_x = (xx + widd - bigx) - get_fixed_pixel_size(5);
2704                     tdxp = xx;
2705                 }
2706                 tdxp += get_textwindow_border_width(play.speech_textwindow_gui) / 2;
2707                 allowShrink = 2;
2708             }
2709             if (game.options[OPT_SPEECHTYPE] == 3)
2710                 overlay_x = 0;
2711             face_talking=add_screen_overlay(overlay_x,ovr_yp,ovr_type,closeupface, closeupface_has_alpha);
2712             facetalkframe = 0;
2713             facetalkwait = viptr->loops[0].frames[0].speed + GetCharacterSpeechAnimationDelay(speakingChar);
2714             facetalkloop = 0;
2715             facetalkview = useview;
2716             facetalkrepeat = (isThought) ? 0 : 1;
2717             facetalkBlinkLoop = 0;
2718             facetalkAllowBlink = 1;
2719             if ((isThought) && (speakingChar->flags & CHF_NOBLINKANDTHINK))
2720                 facetalkAllowBlink = 0;
2721             facetalkchar = &game.chars[aschar];
2722             if (facetalkchar->blinktimer < 0)
2723                 facetalkchar->blinktimer = facetalkchar->blinkinterval;
2724             textcol=-textcol;
2725             overlayPositionFixed = true;
2726         }
2727         else if (useview >= 0) {
2728             // Lucasarts-style speech
2729             our_eip=154;
2730 
2731             oldview = speakingChar->view;
2732             oldloop = speakingChar->loop;
2733             speakingChar->animating = 1 | (GetCharacterSpeechAnimationDelay(speakingChar) << 8);
2734             // only repeat if speech, not thought
2735             if (!isThought)
2736                 speakingChar->animating |= CHANIM_REPEAT;
2737 
2738             speakingChar->view = useview;
2739             speakingChar->frame=0;
2740             speakingChar->flags|=CHF_FIXVIEW;
2741 
2742             if (speakingChar->loop >= views[speakingChar->view].numLoops)
2743             {
2744                 // current character loop is outside the normal talking directions
2745                 speakingChar->loop = 0;
2746             }
2747 
2748             facetalkBlinkLoop = speakingChar->loop;
2749 
2750             if ((speakingChar->loop >= views[speakingChar->view].numLoops) ||
2751                 (views[speakingChar->view].loops[speakingChar->loop].numFrames < 1))
2752             {
2753                 quitprintf("!Unable to display speech because the character %s has an invalid speech view (View %d, loop %d, frame %d)", speakingChar->scrname, speakingChar->view + 1, speakingChar->loop, speakingChar->frame);
2754             }
2755 
2756             // set up the speed of the first frame
2757             speakingChar->wait = GetCharacterSpeechAnimationDelay(speakingChar) +
2758                 views[speakingChar->view].loops[speakingChar->loop].frames[0].speed;
2759 
2760             if (widd < 0) {
2761                 bwidth = play.viewport.GetWidth()/2 + play.viewport.GetWidth()/6;
2762                 // If they are close to the screen edge, make the text narrower
2763                 int relx = multiply_up_coordinate(speakingChar->x) - offsetx;
2764                 if ((relx < play.viewport.GetWidth() / 4) || (relx > play.viewport.GetWidth() - (play.viewport.GetWidth() / 4)))
2765                     bwidth -= play.viewport.GetWidth() / 5;
2766             }
2767             /*   this causes the text to bob up and down as they talk
2768             tdxp = OVR_AUTOPLACE;
2769             tdyp = aschar;*/
2770             if (!isThought)  // set up the lip sync if not thinking
2771                 char_speaking = aschar;
2772 
2773         }
2774     }
2775     else
2776         allowShrink = 1;
2777 
2778     // it wants the centred position, so make it so
2779     if ((xx >= 0) && (tdxp < 0))
2780         tdxp -= widd / 2;
2781 
2782     // if they used DisplaySpeechAt, then use the supplied width
2783     if ((widd > 0) && (isThought == 0))
2784         allowShrink = 0;
2785 
2786     if (isThought)
2787         char_thinking = aschar;
2788 
2789     our_eip=155;
2790     _display_at(tdxp,tdyp,bwidth,texx,0,textcol, isThought, allowShrink, overlayPositionFixed);
2791     our_eip=156;
2792     if ((play.in_conversation > 0) && (game.options[OPT_SPEECHTYPE] == 3))
2793         closeupface = NULL;
2794     if (closeupface!=NULL)
2795         remove_screen_overlay(ovr_type);
2796     screen_is_dirty = 1;
2797     face_talking = -1;
2798     facetalkchar = NULL;
2799     our_eip=157;
2800     if (oldview>=0) {
2801         speakingChar->flags &= ~CHF_FIXVIEW;
2802         if (viewWasLocked)
2803             speakingChar->flags |= CHF_FIXVIEW;
2804         speakingChar->view=oldview;
2805 
2806         // Don't reset the loop in 2.x games
2807         if (loaded_game_file_version > kGameVersion_272)
2808             speakingChar->loop = oldloop;
2809 
2810         speakingChar->animating=0;
2811         speakingChar->frame = charFrameWas;
2812         speakingChar->wait=0;
2813         speakingChar->idleleft = speakingChar->idletime;
2814         // restart the idle animation straight away
2815         charextra[aschar].process_idle_this_time = 1;
2816     }
2817     char_speaking = -1;
2818     char_thinking = -1;
2819     stop_speech();
2820 }
2821 
get_character_currently_talking()2822 int get_character_currently_talking() {
2823     if ((face_talking >= 0) && (facetalkrepeat))
2824         return facetalkchar->index_id;
2825     else if (char_speaking >= 0)
2826         return char_speaking;
2827 
2828     return -1;
2829 }
2830 
DisplaySpeech(const char * texx,int aschar)2831 void DisplaySpeech(const char*texx, int aschar) {
2832     _displayspeech (texx, aschar, -1, -1, -1, 0);
2833 }
2834 
2835 // Calculate which frame of the loop to use for this character of
2836 // speech
GetLipSyncFrame(const char * curtex,int * stroffs)2837 int GetLipSyncFrame (const char *curtex, int *stroffs) {
2838     /*char *frameletters[MAXLIPSYNCFRAMES] =
2839     {"./,/ ", "A", "O", "F/V", "D/N/G/L/R", "B/P/M",
2840     "Y/H/K/Q/C", "I/T/E/X/th", "U/W", "S/Z/J/ch", NULL,
2841     NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};*/
2842 
2843     int bestfit_len = 0, bestfit = game.default_lipsync_frame;
2844     for (int aa = 0; aa < MAXLIPSYNCFRAMES; aa++) {
2845         char *tptr = game.lipSyncFrameLetters[aa];
2846         while (tptr[0] != 0) {
2847             int lenthisbit = strlen(tptr);
2848             if (strchr(tptr, '/'))
2849                 lenthisbit = strchr(tptr, '/') - tptr;
2850 
2851             if ((strnicmp (curtex, tptr, lenthisbit) == 0) && (lenthisbit > bestfit_len)) {
2852                 bestfit = aa;
2853                 bestfit_len = lenthisbit;
2854             }
2855             tptr += lenthisbit;
2856             while (tptr[0] == '/')
2857                 tptr++;
2858         }
2859     }
2860     // If it's an unknown character, use the default frame
2861     if (bestfit_len == 0)
2862         bestfit_len = 1;
2863     *stroffs += bestfit_len;
2864     return bestfit;
2865 }
2866 
update_lip_sync(int talkview,int talkloop,int * talkframeptr)2867 int update_lip_sync(int talkview, int talkloop, int *talkframeptr) {
2868     int talkframe = talkframeptr[0];
2869     int talkwait = 0;
2870 
2871     // lip-sync speech
2872     const char *nowsaying = &text_lips_text[text_lips_offset];
2873     // if it's an apostraphe, skip it (we'll, I'll, etc)
2874     if (nowsaying[0] == '\'') {
2875         text_lips_offset++;
2876         nowsaying++;
2877     }
2878 
2879     if (text_lips_offset >= (int)strlen(text_lips_text))
2880         talkframe = 0;
2881     else {
2882         talkframe = GetLipSyncFrame (nowsaying, &text_lips_offset);
2883         if (talkframe >= views[talkview].loops[talkloop].numFrames)
2884             talkframe = 0;
2885     }
2886 
2887     talkwait = loops_per_character + views[talkview].loops[talkloop].frames[talkframe].speed;
2888 
2889     talkframeptr[0] = talkframe;
2890     return talkwait;
2891 }
2892 
2893 //=============================================================================
2894 //
2895 // Script API Functions
2896 //
2897 //=============================================================================
2898 
2899 #include "debug/out.h"
2900 #include "script/script_api.h"
2901 #include "script/script_runtime.h"
2902 #include "ac/dynobj/scriptstring.h"
2903 
2904 extern ScriptString myScriptStringImpl;
2905 
2906 // void | CharacterInfo *chaa, ScriptInvItem *invi, int addIndex
Sc_Character_AddInventory(void * self,const RuntimeScriptValue * params,int32_t param_count)2907 RuntimeScriptValue Sc_Character_AddInventory(void *self, const RuntimeScriptValue *params, int32_t param_count)
2908 {
2909     API_OBJCALL_VOID_POBJ_PINT(CharacterInfo, Character_AddInventory, ScriptInvItem);
2910 }
2911 
2912 // void | CharacterInfo *chaa, int x, int y
Sc_Character_AddWaypoint(void * self,const RuntimeScriptValue * params,int32_t param_count)2913 RuntimeScriptValue Sc_Character_AddWaypoint(void *self, const RuntimeScriptValue *params, int32_t param_count)
2914 {
2915     API_OBJCALL_VOID_PINT2(CharacterInfo, Character_AddWaypoint);
2916 }
2917 
2918 // void | CharacterInfo *chaa, int loop, int delay, int repeat, int blocking, int direction
Sc_Character_Animate(void * self,const RuntimeScriptValue * params,int32_t param_count)2919 RuntimeScriptValue Sc_Character_Animate(void *self, const RuntimeScriptValue *params, int32_t param_count)
2920 {
2921     API_OBJCALL_VOID_PINT5(CharacterInfo, Character_Animate);
2922 }
2923 
2924 // void | CharacterInfo *chaa, int room, int x, int y
Sc_Character_ChangeRoom(void * self,const RuntimeScriptValue * params,int32_t param_count)2925 RuntimeScriptValue Sc_Character_ChangeRoom(void *self, const RuntimeScriptValue *params, int32_t param_count)
2926 {
2927     API_OBJCALL_VOID_PINT3(CharacterInfo, Character_ChangeRoom);
2928 }
2929 
Sc_Character_ChangeRoomSetLoop(void * self,const RuntimeScriptValue * params,int32_t param_count)2930 RuntimeScriptValue Sc_Character_ChangeRoomSetLoop(void *self, const RuntimeScriptValue *params, int32_t param_count)
2931 {
2932     API_OBJCALL_VOID_PINT4(CharacterInfo, Character_ChangeRoomSetLoop);
2933 }
2934 
2935 // void | CharacterInfo *chaa, int room, int newPos
Sc_Character_ChangeRoomAutoPosition(void * self,const RuntimeScriptValue * params,int32_t param_count)2936 RuntimeScriptValue Sc_Character_ChangeRoomAutoPosition(void *self, const RuntimeScriptValue *params, int32_t param_count)
2937 {
2938     API_OBJCALL_VOID_PINT2(CharacterInfo, Character_ChangeRoomAutoPosition);
2939 }
2940 
2941 // void | CharacterInfo *chap, int vii
Sc_Character_ChangeView(void * self,const RuntimeScriptValue * params,int32_t param_count)2942 RuntimeScriptValue Sc_Character_ChangeView(void *self, const RuntimeScriptValue *params, int32_t param_count)
2943 {
2944     API_OBJCALL_VOID_PINT(CharacterInfo, Character_ChangeView);
2945 }
2946 
2947 // void | CharacterInfo *char1, CharacterInfo *char2, int blockingStyle
Sc_Character_FaceCharacter(void * self,const RuntimeScriptValue * params,int32_t param_count)2948 RuntimeScriptValue Sc_Character_FaceCharacter(void *self, const RuntimeScriptValue *params, int32_t param_count)
2949 {
2950     API_OBJCALL_VOID_POBJ_PINT(CharacterInfo, Character_FaceCharacter, CharacterInfo);
2951 }
2952 
2953 // void | CharacterInfo *char1, int direction, int blockingStyle
Sc_Character_FaceDirection(void * self,const RuntimeScriptValue * params,int32_t param_count)2954 RuntimeScriptValue Sc_Character_FaceDirection(void *self, const RuntimeScriptValue *params, int32_t param_count)
2955 {
2956     API_OBJCALL_VOID_PINT2(CharacterInfo, Character_FaceDirection);
2957 }
2958 
2959 // void | CharacterInfo *char1, int xx, int yy, int blockingStyle
Sc_Character_FaceLocation(void * self,const RuntimeScriptValue * params,int32_t param_count)2960 RuntimeScriptValue Sc_Character_FaceLocation(void *self, const RuntimeScriptValue *params, int32_t param_count)
2961 {
2962     API_OBJCALL_VOID_PINT3(CharacterInfo, Character_FaceLocation);
2963 }
2964 
2965 // void | CharacterInfo *char1, ScriptObject *obj, int blockingStyle
Sc_Character_FaceObject(void * self,const RuntimeScriptValue * params,int32_t param_count)2966 RuntimeScriptValue Sc_Character_FaceObject(void *self, const RuntimeScriptValue *params, int32_t param_count)
2967 {
2968     API_OBJCALL_VOID_POBJ_PINT(CharacterInfo, Character_FaceObject, ScriptObject);
2969 }
2970 
2971 // void | CharacterInfo *chaa, CharacterInfo *tofollow, int distaway, int eagerness
Sc_Character_FollowCharacter(void * self,const RuntimeScriptValue * params,int32_t param_count)2972 RuntimeScriptValue Sc_Character_FollowCharacter(void *self, const RuntimeScriptValue *params, int32_t param_count)
2973 {
2974     API_OBJCALL_VOID_POBJ_PINT2(CharacterInfo, Character_FollowCharacter, CharacterInfo);
2975 }
2976 
2977 // int (CharacterInfo *chaa, const char *property)
Sc_Character_GetProperty(void * self,const RuntimeScriptValue * params,int32_t param_count)2978 RuntimeScriptValue Sc_Character_GetProperty(void *self, const RuntimeScriptValue *params, int32_t param_count)
2979 {
2980     API_OBJCALL_INT_POBJ(CharacterInfo, Character_GetProperty, const char);
2981 }
2982 
2983 // void (CharacterInfo *chaa, const char *property, char *bufer)
Sc_Character_GetPropertyText(void * self,const RuntimeScriptValue * params,int32_t param_count)2984 RuntimeScriptValue Sc_Character_GetPropertyText(void *self, const RuntimeScriptValue *params, int32_t param_count)
2985 {
2986     API_OBJCALL_VOID_POBJ2(CharacterInfo, Character_GetPropertyText, const char, char);
2987 }
2988 
2989 // const char* (CharacterInfo *chaa, const char *property)
Sc_Character_GetTextProperty(void * self,const RuntimeScriptValue * params,int32_t param_count)2990 RuntimeScriptValue Sc_Character_GetTextProperty(void *self, const RuntimeScriptValue *params, int32_t param_count)
2991 {
2992     API_OBJCALL_OBJ_POBJ(CharacterInfo, const char, myScriptStringImpl, Character_GetTextProperty, const char);
2993 }
2994 
Sc_Character_SetProperty(void * self,const RuntimeScriptValue * params,int32_t param_count)2995 RuntimeScriptValue Sc_Character_SetProperty(void *self, const RuntimeScriptValue *params, int32_t param_count)
2996 {
2997     API_OBJCALL_BOOL_POBJ_PINT(CharacterInfo, Character_SetProperty, const char);
2998 }
2999 
Sc_Character_SetTextProperty(void * self,const RuntimeScriptValue * params,int32_t param_count)3000 RuntimeScriptValue Sc_Character_SetTextProperty(void *self, const RuntimeScriptValue *params, int32_t param_count)
3001 {
3002     API_OBJCALL_BOOL_POBJ2(CharacterInfo, Character_SetTextProperty, const char, const char);
3003 }
3004 
3005 // int (CharacterInfo *chaa, ScriptInvItem *invi)
Sc_Character_HasInventory(void * self,const RuntimeScriptValue * params,int32_t param_count)3006 RuntimeScriptValue Sc_Character_HasInventory(void *self, const RuntimeScriptValue *params, int32_t param_count)
3007 {
3008     API_OBJCALL_INT_POBJ(CharacterInfo, Character_HasInventory, ScriptInvItem);
3009 }
3010 
3011 // int (CharacterInfo *char1, CharacterInfo *char2)
Sc_Character_IsCollidingWithChar(void * self,const RuntimeScriptValue * params,int32_t param_count)3012 RuntimeScriptValue Sc_Character_IsCollidingWithChar(void *self, const RuntimeScriptValue *params, int32_t param_count)
3013 {
3014     API_OBJCALL_INT_POBJ(CharacterInfo, Character_IsCollidingWithChar, CharacterInfo);
3015 }
3016 
3017 // int (CharacterInfo *chin, ScriptObject *objid)
Sc_Character_IsCollidingWithObject(void * self,const RuntimeScriptValue * params,int32_t param_count)3018 RuntimeScriptValue Sc_Character_IsCollidingWithObject(void *self, const RuntimeScriptValue *params, int32_t param_count)
3019 {
3020     API_OBJCALL_INT_POBJ(CharacterInfo, Character_IsCollidingWithObject, ScriptObject);
3021 }
3022 
Sc_Character_IsInteractionAvailable(void * self,const RuntimeScriptValue * params,int32_t param_count)3023 RuntimeScriptValue Sc_Character_IsInteractionAvailable(void *self, const RuntimeScriptValue *params, int32_t param_count)
3024 {
3025     API_OBJCALL_BOOL_PINT(CharacterInfo, Character_IsInteractionAvailable);
3026 }
3027 
3028 // void (CharacterInfo *chap, int vii)
Sc_Character_LockView(void * self,const RuntimeScriptValue * params,int32_t param_count)3029 RuntimeScriptValue Sc_Character_LockView(void *self, const RuntimeScriptValue *params, int32_t param_count)
3030 {
3031     API_OBJCALL_VOID_PINT(CharacterInfo, Character_LockView);
3032 }
3033 
3034 // void (CharacterInfo *chap, int vii, int stopMoving)
Sc_Character_LockViewEx(void * self,const RuntimeScriptValue * params,int32_t param_count)3035 RuntimeScriptValue Sc_Character_LockViewEx(void *self, const RuntimeScriptValue *params, int32_t param_count)
3036 {
3037     API_OBJCALL_VOID_PINT2(CharacterInfo, Character_LockViewEx);
3038 }
3039 
3040 // void (CharacterInfo *chap, int vii, int loop, int align)
Sc_Character_LockViewAligned(void * self,const RuntimeScriptValue * params,int32_t param_count)3041 RuntimeScriptValue Sc_Character_LockViewAligned(void *self, const RuntimeScriptValue *params, int32_t param_count)
3042 {
3043     API_OBJCALL_VOID_PINT3(CharacterInfo, Character_LockViewAligned);
3044 }
3045 
3046 // void (CharacterInfo *chap, int vii, int loop, int align, int stopMoving)
Sc_Character_LockViewAlignedEx(void * self,const RuntimeScriptValue * params,int32_t param_count)3047 RuntimeScriptValue Sc_Character_LockViewAlignedEx(void *self, const RuntimeScriptValue *params, int32_t param_count)
3048 {
3049     API_OBJCALL_VOID_PINT4(CharacterInfo, Character_LockViewAlignedEx);
3050 }
3051 
3052 // void (CharacterInfo *chaa, int view, int loop, int frame)
Sc_Character_LockViewFrame(void * self,const RuntimeScriptValue * params,int32_t param_count)3053 RuntimeScriptValue Sc_Character_LockViewFrame(void *self, const RuntimeScriptValue *params, int32_t param_count)
3054 {
3055     API_OBJCALL_VOID_PINT3(CharacterInfo, Character_LockViewFrame);
3056 }
3057 
3058 // void (CharacterInfo *chaa, int view, int loop, int frame, int stopMoving)
Sc_Character_LockViewFrameEx(void * self,const RuntimeScriptValue * params,int32_t param_count)3059 RuntimeScriptValue Sc_Character_LockViewFrameEx(void *self, const RuntimeScriptValue *params, int32_t param_count)
3060 {
3061     API_OBJCALL_VOID_PINT4(CharacterInfo, Character_LockViewFrameEx);
3062 }
3063 
3064 // void (CharacterInfo *chap, int vii, int xoffs, int yoffs)
Sc_Character_LockViewOffset(void * self,const RuntimeScriptValue * params,int32_t param_count)3065 RuntimeScriptValue Sc_Character_LockViewOffset(void *self, const RuntimeScriptValue *params, int32_t param_count)
3066 {
3067     API_OBJCALL_VOID_PINT3(CharacterInfo, Character_LockViewOffset);
3068 }
3069 
3070 // void (CharacterInfo *chap, int vii, int xoffs, int yoffs, int stopMoving)
Sc_Character_LockViewOffsetEx(void * self,const RuntimeScriptValue * params,int32_t param_count)3071 RuntimeScriptValue Sc_Character_LockViewOffsetEx(void *self, const RuntimeScriptValue *params, int32_t param_count)
3072 {
3073     API_OBJCALL_VOID_PINT4(CharacterInfo, Character_LockViewOffsetEx);
3074 }
3075 
3076 // void (CharacterInfo *chap, ScriptInvItem *invi)
Sc_Character_LoseInventory(void * self,const RuntimeScriptValue * params,int32_t param_count)3077 RuntimeScriptValue Sc_Character_LoseInventory(void *self, const RuntimeScriptValue *params, int32_t param_count)
3078 {
3079     API_OBJCALL_VOID_POBJ(CharacterInfo, Character_LoseInventory, ScriptInvItem);
3080 }
3081 
3082 // void (CharacterInfo *chaa, int x, int y, int blocking, int direct)
Sc_Character_Move(void * self,const RuntimeScriptValue * params,int32_t param_count)3083 RuntimeScriptValue Sc_Character_Move(void *self, const RuntimeScriptValue *params, int32_t param_count)
3084 {
3085     API_OBJCALL_VOID_PINT4(CharacterInfo, Character_Move);
3086 }
3087 
3088 // void (CharacterInfo *chap)
Sc_Character_PlaceOnWalkableArea(void * self,const RuntimeScriptValue * params,int32_t param_count)3089 RuntimeScriptValue Sc_Character_PlaceOnWalkableArea(void *self, const RuntimeScriptValue *params, int32_t param_count)
3090 {
3091     API_OBJCALL_VOID(CharacterInfo, Character_PlaceOnWalkableArea);
3092 }
3093 
3094 // void (CharacterInfo *chaa)
Sc_Character_RemoveTint(void * self,const RuntimeScriptValue * params,int32_t param_count)3095 RuntimeScriptValue Sc_Character_RemoveTint(void *self, const RuntimeScriptValue *params, int32_t param_count)
3096 {
3097     API_OBJCALL_VOID(CharacterInfo, Character_RemoveTint);
3098 }
3099 
3100 // void (CharacterInfo *chaa, int mood)
Sc_Character_RunInteraction(void * self,const RuntimeScriptValue * params,int32_t param_count)3101 RuntimeScriptValue Sc_Character_RunInteraction(void *self, const RuntimeScriptValue *params, int32_t param_count)
3102 {
3103     API_OBJCALL_VOID_PINT(CharacterInfo, Character_RunInteraction);
3104 }
3105 
3106 // void (CharacterInfo *chaa, const char *texx, ...)
Sc_Character_Say(void * self,const RuntimeScriptValue * params,int32_t param_count)3107 RuntimeScriptValue Sc_Character_Say(void *self, const RuntimeScriptValue *params, int32_t param_count)
3108 {
3109     API_OBJCALL_SCRIPT_SPRINTF(Character_Say, 1);
3110     Character_Say((CharacterInfo*)self, scsf_buffer);
3111     return RuntimeScriptValue((int32_t)0);
3112 }
3113 
3114 // void (CharacterInfo *chaa, int x, int y, int width, const char *texx)
Sc_Character_SayAt(void * self,const RuntimeScriptValue * params,int32_t param_count)3115 RuntimeScriptValue Sc_Character_SayAt(void *self, const RuntimeScriptValue *params, int32_t param_count)
3116 {
3117     API_OBJCALL_VOID_PINT3_POBJ(CharacterInfo, Character_SayAt, const char);
3118 }
3119 
3120 // ScriptOverlay* (CharacterInfo *chaa, const char *texx)
Sc_Character_SayBackground(void * self,const RuntimeScriptValue * params,int32_t param_count)3121 RuntimeScriptValue Sc_Character_SayBackground(void *self, const RuntimeScriptValue *params, int32_t param_count)
3122 {
3123     API_OBJCALL_OBJAUTO_POBJ(CharacterInfo, ScriptOverlay, Character_SayBackground, const char);
3124 }
3125 
3126 // void (CharacterInfo *chaa)
Sc_Character_SetAsPlayer(void * self,const RuntimeScriptValue * params,int32_t param_count)3127 RuntimeScriptValue Sc_Character_SetAsPlayer(void *self, const RuntimeScriptValue *params, int32_t param_count)
3128 {
3129     API_OBJCALL_VOID(CharacterInfo, Character_SetAsPlayer);
3130 }
3131 
3132 // void (CharacterInfo *chaa, int iview, int itime)
Sc_Character_SetIdleView(void * self,const RuntimeScriptValue * params,int32_t param_count)3133 RuntimeScriptValue Sc_Character_SetIdleView(void *self, const RuntimeScriptValue *params, int32_t param_count)
3134 {
3135     API_OBJCALL_VOID_PINT2(CharacterInfo, Character_SetIdleView);
3136 }
3137 
Sc_Character_HasExplicitLight(void * self,const RuntimeScriptValue * params,int32_t param_count)3138 RuntimeScriptValue Sc_Character_HasExplicitLight(void *self, const RuntimeScriptValue *params, int32_t param_count)
3139 {
3140     API_OBJCALL_BOOL(CharacterInfo, Character_GetHasExplicitLight);
3141 }
3142 
Sc_Character_GetLightLevel(void * self,const RuntimeScriptValue * params,int32_t param_count)3143 RuntimeScriptValue Sc_Character_GetLightLevel(void *self, const RuntimeScriptValue *params, int32_t param_count)
3144 {
3145     API_OBJCALL_INT(CharacterInfo, Character_GetLightLevel);
3146 }
3147 
Sc_Character_SetLightLevel(void * self,const RuntimeScriptValue * params,int32_t param_count)3148 RuntimeScriptValue Sc_Character_SetLightLevel(void *self, const RuntimeScriptValue *params, int32_t param_count)
3149 {
3150     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetLightLevel);
3151 }
3152 
Sc_Character_GetTintBlue(void * self,const RuntimeScriptValue * params,int32_t param_count)3153 RuntimeScriptValue Sc_Character_GetTintBlue(void *self, const RuntimeScriptValue *params, int32_t param_count)
3154 {
3155     API_OBJCALL_INT(CharacterInfo, Character_GetTintBlue);
3156 }
3157 
Sc_Character_GetTintGreen(void * self,const RuntimeScriptValue * params,int32_t param_count)3158 RuntimeScriptValue Sc_Character_GetTintGreen(void *self, const RuntimeScriptValue *params, int32_t param_count)
3159 {
3160     API_OBJCALL_INT(CharacterInfo, Character_GetTintGreen);
3161 }
3162 
Sc_Character_GetTintRed(void * self,const RuntimeScriptValue * params,int32_t param_count)3163 RuntimeScriptValue Sc_Character_GetTintRed(void *self, const RuntimeScriptValue *params, int32_t param_count)
3164 {
3165     API_OBJCALL_INT(CharacterInfo, Character_GetTintRed);
3166 }
3167 
Sc_Character_GetTintSaturation(void * self,const RuntimeScriptValue * params,int32_t param_count)3168 RuntimeScriptValue Sc_Character_GetTintSaturation(void *self, const RuntimeScriptValue *params, int32_t param_count)
3169 {
3170     API_OBJCALL_INT(CharacterInfo, Character_GetTintSaturation);
3171 }
3172 
Sc_Character_GetTintLuminance(void * self,const RuntimeScriptValue * params,int32_t param_count)3173 RuntimeScriptValue Sc_Character_GetTintLuminance(void *self, const RuntimeScriptValue *params, int32_t param_count)
3174 {
3175     API_OBJCALL_INT(CharacterInfo, Character_GetTintLuminance);
3176 }
3177 
3178 /*
3179 RuntimeScriptValue Sc_Character_SetOption(void *self, const RuntimeScriptValue *params, int32_t param_count)
3180 {
3181 }
3182 */
3183 
3184 // void (CharacterInfo *chaa, int xspeed, int yspeed)
Sc_Character_SetSpeed(void * self,const RuntimeScriptValue * params,int32_t param_count)3185 RuntimeScriptValue Sc_Character_SetSpeed(void *self, const RuntimeScriptValue *params, int32_t param_count)
3186 {
3187     API_OBJCALL_VOID_PINT2(CharacterInfo, Character_SetSpeed);
3188 }
3189 
3190 // void (CharacterInfo *charp)
Sc_Character_StopMoving(void * self,const RuntimeScriptValue * params,int32_t param_count)3191 RuntimeScriptValue Sc_Character_StopMoving(void *self, const RuntimeScriptValue *params, int32_t param_count)
3192 {
3193     API_OBJCALL_VOID(CharacterInfo, Character_StopMoving);
3194 }
3195 
3196 // void (CharacterInfo *chaa, const char *texx, ...)
Sc_Character_Think(void * self,const RuntimeScriptValue * params,int32_t param_count)3197 RuntimeScriptValue Sc_Character_Think(void *self, const RuntimeScriptValue *params, int32_t param_count)
3198 {
3199     API_OBJCALL_SCRIPT_SPRINTF(Character_Think, 1);
3200     Character_Think((CharacterInfo*)self, scsf_buffer);
3201     return RuntimeScriptValue((int32_t)0);
3202 }
3203 
3204 //void (CharacterInfo *chaa, int red, int green, int blue, int opacity, int luminance)
Sc_Character_Tint(void * self,const RuntimeScriptValue * params,int32_t param_count)3205 RuntimeScriptValue Sc_Character_Tint(void *self, const RuntimeScriptValue *params, int32_t param_count)
3206 {
3207     API_OBJCALL_VOID_PINT5(CharacterInfo, Character_Tint);
3208 }
3209 
3210 // void (CharacterInfo *chaa)
Sc_Character_UnlockView(void * self,const RuntimeScriptValue * params,int32_t param_count)3211 RuntimeScriptValue Sc_Character_UnlockView(void *self, const RuntimeScriptValue *params, int32_t param_count)
3212 {
3213     API_OBJCALL_VOID(CharacterInfo, Character_UnlockView);
3214 }
3215 
3216 // void (CharacterInfo *chaa, int stopMoving)
Sc_Character_UnlockViewEx(void * self,const RuntimeScriptValue * params,int32_t param_count)3217 RuntimeScriptValue Sc_Character_UnlockViewEx(void *self, const RuntimeScriptValue *params, int32_t param_count)
3218 {
3219     API_OBJCALL_VOID_PINT(CharacterInfo, Character_UnlockViewEx);
3220 }
3221 
3222 // void (CharacterInfo *chaa, int x, int y, int blocking, int direct)
Sc_Character_Walk(void * self,const RuntimeScriptValue * params,int32_t param_count)3223 RuntimeScriptValue Sc_Character_Walk(void *self, const RuntimeScriptValue *params, int32_t param_count)
3224 {
3225     API_OBJCALL_VOID_PINT4(CharacterInfo, Character_Walk);
3226 }
3227 
3228 // void (CharacterInfo *chaa, int xx, int yy, int blocking)
Sc_Character_WalkStraight(void * self,const RuntimeScriptValue * params,int32_t param_count)3229 RuntimeScriptValue Sc_Character_WalkStraight(void *self, const RuntimeScriptValue *params, int32_t param_count)
3230 {
3231     API_OBJCALL_VOID_PINT3(CharacterInfo, Character_WalkStraight);
3232 }
3233 
3234 // CharacterInfo *(int xx, int yy)
Sc_GetCharacterAtLocation(const RuntimeScriptValue * params,int32_t param_count)3235 RuntimeScriptValue Sc_GetCharacterAtLocation(const RuntimeScriptValue *params, int32_t param_count)
3236 {
3237     API_SCALL_OBJ_PINT2(CharacterInfo, ccDynamicCharacter, GetCharacterAtLocation);
3238 }
3239 
3240 // ScriptInvItem* (CharacterInfo *chaa)
Sc_Character_GetActiveInventory(void * self,const RuntimeScriptValue * params,int32_t param_count)3241 RuntimeScriptValue Sc_Character_GetActiveInventory(void *self, const RuntimeScriptValue *params, int32_t param_count)
3242 {
3243     API_OBJCALL_OBJ(CharacterInfo, ScriptInvItem, ccDynamicInv, Character_GetActiveInventory);
3244 }
3245 
3246 // void (CharacterInfo *chaa, ScriptInvItem* iit)
Sc_Character_SetActiveInventory(void * self,const RuntimeScriptValue * params,int32_t param_count)3247 RuntimeScriptValue Sc_Character_SetActiveInventory(void *self, const RuntimeScriptValue *params, int32_t param_count)
3248 {
3249     API_OBJCALL_VOID_POBJ(CharacterInfo, Character_SetActiveInventory, ScriptInvItem);
3250 }
3251 
3252 // int (CharacterInfo *chaa)
Sc_Character_GetAnimating(void * self,const RuntimeScriptValue * params,int32_t param_count)3253 RuntimeScriptValue Sc_Character_GetAnimating(void *self, const RuntimeScriptValue *params, int32_t param_count)
3254 {
3255     API_OBJCALL_INT(CharacterInfo, Character_GetAnimating);
3256 }
3257 
3258 // int (CharacterInfo *chaa)
Sc_Character_GetAnimationSpeed(void * self,const RuntimeScriptValue * params,int32_t param_count)3259 RuntimeScriptValue Sc_Character_GetAnimationSpeed(void *self, const RuntimeScriptValue *params, int32_t param_count)
3260 {
3261     API_OBJCALL_INT(CharacterInfo, Character_GetAnimationSpeed);
3262 }
3263 
3264 // void (CharacterInfo *chaa, int newval)
Sc_Character_SetAnimationSpeed(void * self,const RuntimeScriptValue * params,int32_t param_count)3265 RuntimeScriptValue Sc_Character_SetAnimationSpeed(void *self, const RuntimeScriptValue *params, int32_t param_count)
3266 {
3267     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetAnimationSpeed);
3268 }
3269 
3270 // int (CharacterInfo *chaa)
Sc_Character_GetBaseline(void * self,const RuntimeScriptValue * params,int32_t param_count)3271 RuntimeScriptValue Sc_Character_GetBaseline(void *self, const RuntimeScriptValue *params, int32_t param_count)
3272 {
3273     API_OBJCALL_INT(CharacterInfo, Character_GetBaseline);
3274 }
3275 
3276 // void (CharacterInfo *chaa, int basel)
Sc_Character_SetBaseline(void * self,const RuntimeScriptValue * params,int32_t param_count)3277 RuntimeScriptValue Sc_Character_SetBaseline(void *self, const RuntimeScriptValue *params, int32_t param_count)
3278 {
3279     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetBaseline);
3280 }
3281 
3282 // int (CharacterInfo *chaa)
Sc_Character_GetBlinkInterval(void * self,const RuntimeScriptValue * params,int32_t param_count)3283 RuntimeScriptValue Sc_Character_GetBlinkInterval(void *self, const RuntimeScriptValue *params, int32_t param_count)
3284 {
3285     API_OBJCALL_INT(CharacterInfo, Character_GetBlinkInterval);
3286 }
3287 
3288 // void (CharacterInfo *chaa, int interval)
Sc_Character_SetBlinkInterval(void * self,const RuntimeScriptValue * params,int32_t param_count)3289 RuntimeScriptValue Sc_Character_SetBlinkInterval(void *self, const RuntimeScriptValue *params, int32_t param_count)
3290 {
3291     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetBlinkInterval);
3292 }
3293 
3294 // int (CharacterInfo *chaa)
Sc_Character_GetBlinkView(void * self,const RuntimeScriptValue * params,int32_t param_count)3295 RuntimeScriptValue Sc_Character_GetBlinkView(void *self, const RuntimeScriptValue *params, int32_t param_count)
3296 {
3297     API_OBJCALL_INT(CharacterInfo, Character_GetBlinkView);
3298 }
3299 
3300 // void (CharacterInfo *chaa, int vii)
Sc_Character_SetBlinkView(void * self,const RuntimeScriptValue * params,int32_t param_count)3301 RuntimeScriptValue Sc_Character_SetBlinkView(void *self, const RuntimeScriptValue *params, int32_t param_count)
3302 {
3303     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetBlinkView);
3304 }
3305 
3306 // int (CharacterInfo *chaa)
Sc_Character_GetBlinkWhileThinking(void * self,const RuntimeScriptValue * params,int32_t param_count)3307 RuntimeScriptValue Sc_Character_GetBlinkWhileThinking(void *self, const RuntimeScriptValue *params, int32_t param_count)
3308 {
3309     API_OBJCALL_INT(CharacterInfo, Character_GetBlinkWhileThinking);
3310 }
3311 
3312 // void (CharacterInfo *chaa, int yesOrNo)
Sc_Character_SetBlinkWhileThinking(void * self,const RuntimeScriptValue * params,int32_t param_count)3313 RuntimeScriptValue Sc_Character_SetBlinkWhileThinking(void *self, const RuntimeScriptValue *params, int32_t param_count)
3314 {
3315     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetBlinkWhileThinking);
3316 }
3317 
3318 // int (CharacterInfo *chaa)
Sc_Character_GetBlockingHeight(void * self,const RuntimeScriptValue * params,int32_t param_count)3319 RuntimeScriptValue Sc_Character_GetBlockingHeight(void *self, const RuntimeScriptValue *params, int32_t param_count)
3320 {
3321     API_OBJCALL_INT(CharacterInfo, Character_GetBlockingHeight);
3322 }
3323 
3324 // void (CharacterInfo *chaa, int hit)
Sc_Character_SetBlockingHeight(void * self,const RuntimeScriptValue * params,int32_t param_count)3325 RuntimeScriptValue Sc_Character_SetBlockingHeight(void *self, const RuntimeScriptValue *params, int32_t param_count)
3326 {
3327     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetBlockingHeight);
3328 }
3329 
3330 // int (CharacterInfo *chaa)
Sc_Character_GetBlockingWidth(void * self,const RuntimeScriptValue * params,int32_t param_count)3331 RuntimeScriptValue Sc_Character_GetBlockingWidth(void *self, const RuntimeScriptValue *params, int32_t param_count)
3332 {
3333     API_OBJCALL_INT(CharacterInfo, Character_GetBlockingWidth);
3334 }
3335 
3336 // void (CharacterInfo *chaa, int wid)
Sc_Character_SetBlockingWidth(void * self,const RuntimeScriptValue * params,int32_t param_count)3337 RuntimeScriptValue Sc_Character_SetBlockingWidth(void *self, const RuntimeScriptValue *params, int32_t param_count)
3338 {
3339     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetBlockingWidth);
3340 }
3341 
3342 // int (CharacterInfo *chaa)
Sc_Character_GetClickable(void * self,const RuntimeScriptValue * params,int32_t param_count)3343 RuntimeScriptValue Sc_Character_GetClickable(void *self, const RuntimeScriptValue *params, int32_t param_count)
3344 {
3345     API_OBJCALL_INT(CharacterInfo, Character_GetClickable);
3346 }
3347 
3348 // void (CharacterInfo *chaa, int clik)
Sc_Character_SetClickable(void * self,const RuntimeScriptValue * params,int32_t param_count)3349 RuntimeScriptValue Sc_Character_SetClickable(void *self, const RuntimeScriptValue *params, int32_t param_count)
3350 {
3351     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetClickable);
3352 }
3353 
3354 // int (CharacterInfo *chaa)
Sc_Character_GetDiagonalWalking(void * self,const RuntimeScriptValue * params,int32_t param_count)3355 RuntimeScriptValue Sc_Character_GetDiagonalWalking(void *self, const RuntimeScriptValue *params, int32_t param_count)
3356 {
3357     API_OBJCALL_INT(CharacterInfo, Character_GetDiagonalWalking);
3358 }
3359 
3360 // void (CharacterInfo *chaa, int yesorno)
Sc_Character_SetDiagonalWalking(void * self,const RuntimeScriptValue * params,int32_t param_count)3361 RuntimeScriptValue Sc_Character_SetDiagonalWalking(void *self, const RuntimeScriptValue *params, int32_t param_count)
3362 {
3363     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetDiagonalWalking);
3364 }
3365 
3366 // int (CharacterInfo *chaa)
Sc_Character_GetFrame(void * self,const RuntimeScriptValue * params,int32_t param_count)3367 RuntimeScriptValue Sc_Character_GetFrame(void *self, const RuntimeScriptValue *params, int32_t param_count)
3368 {
3369     API_OBJCALL_INT(CharacterInfo, Character_GetFrame);
3370 }
3371 
3372 // void (CharacterInfo *chaa, int newval)
Sc_Character_SetFrame(void * self,const RuntimeScriptValue * params,int32_t param_count)3373 RuntimeScriptValue Sc_Character_SetFrame(void *self, const RuntimeScriptValue *params, int32_t param_count)
3374 {
3375     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetFrame);
3376 }
3377 
Sc_Character_GetHasExplicitTint(void * self,const RuntimeScriptValue * params,int32_t param_count)3378 RuntimeScriptValue Sc_Character_GetHasExplicitTint(void *self, const RuntimeScriptValue *params, int32_t param_count)
3379 {
3380     API_OBJCALL_INT(CharacterInfo, Character_GetHasExplicitTint);
3381 }
3382 
3383 // int (CharacterInfo *chaa)
Sc_Character_GetID(void * self,const RuntimeScriptValue * params,int32_t param_count)3384 RuntimeScriptValue Sc_Character_GetID(void *self, const RuntimeScriptValue *params, int32_t param_count)
3385 {
3386     API_OBJCALL_INT(CharacterInfo, Character_GetID);
3387 }
3388 
3389 // int (CharacterInfo *chaa)
Sc_Character_GetIdleView(void * self,const RuntimeScriptValue * params,int32_t param_count)3390 RuntimeScriptValue Sc_Character_GetIdleView(void *self, const RuntimeScriptValue *params, int32_t param_count)
3391 {
3392     API_OBJCALL_INT(CharacterInfo, Character_GetIdleView);
3393 }
3394 
3395 // int (CharacterInfo *chaa, int index)
Sc_Character_GetIInventoryQuantity(void * self,const RuntimeScriptValue * params,int32_t param_count)3396 RuntimeScriptValue Sc_Character_GetIInventoryQuantity(void *self, const RuntimeScriptValue *params, int32_t param_count)
3397 {
3398     API_OBJCALL_INT_PINT(CharacterInfo, Character_GetIInventoryQuantity);
3399 }
3400 
3401 // void (CharacterInfo *chaa, int index, int quant)
Sc_Character_SetIInventoryQuantity(void * self,const RuntimeScriptValue * params,int32_t param_count)3402 RuntimeScriptValue Sc_Character_SetIInventoryQuantity(void *self, const RuntimeScriptValue *params, int32_t param_count)
3403 {
3404     API_OBJCALL_VOID_PINT2(CharacterInfo, Character_SetIInventoryQuantity);
3405 }
3406 
3407 // int (CharacterInfo *chaa)
Sc_Character_GetIgnoreLighting(void * self,const RuntimeScriptValue * params,int32_t param_count)3408 RuntimeScriptValue Sc_Character_GetIgnoreLighting(void *self, const RuntimeScriptValue *params, int32_t param_count)
3409 {
3410     API_OBJCALL_INT(CharacterInfo, Character_GetIgnoreLighting);
3411 }
3412 
3413 // void (CharacterInfo *chaa, int yesorno)
Sc_Character_SetIgnoreLighting(void * self,const RuntimeScriptValue * params,int32_t param_count)3414 RuntimeScriptValue Sc_Character_SetIgnoreLighting(void *self, const RuntimeScriptValue *params, int32_t param_count)
3415 {
3416     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetIgnoreLighting);
3417 }
3418 
3419 // int (CharacterInfo *chaa)
Sc_Character_GetIgnoreScaling(void * self,const RuntimeScriptValue * params,int32_t param_count)3420 RuntimeScriptValue Sc_Character_GetIgnoreScaling(void *self, const RuntimeScriptValue *params, int32_t param_count)
3421 {
3422     API_OBJCALL_INT(CharacterInfo, Character_GetIgnoreScaling);
3423 }
3424 
3425 // void (CharacterInfo *chaa, int yesorno)
Sc_Character_SetIgnoreScaling(void * self,const RuntimeScriptValue * params,int32_t param_count)3426 RuntimeScriptValue Sc_Character_SetIgnoreScaling(void *self, const RuntimeScriptValue *params, int32_t param_count)
3427 {
3428     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetIgnoreScaling);
3429 }
3430 
3431 // int (CharacterInfo *chaa)
Sc_Character_GetIgnoreWalkbehinds(void * self,const RuntimeScriptValue * params,int32_t param_count)3432 RuntimeScriptValue Sc_Character_GetIgnoreWalkbehinds(void *self, const RuntimeScriptValue *params, int32_t param_count)
3433 {
3434     API_OBJCALL_INT(CharacterInfo, Character_GetIgnoreWalkbehinds);
3435 }
3436 
3437 // void (CharacterInfo *chaa, int yesorno)
Sc_Character_SetIgnoreWalkbehinds(void * self,const RuntimeScriptValue * params,int32_t param_count)3438 RuntimeScriptValue Sc_Character_SetIgnoreWalkbehinds(void *self, const RuntimeScriptValue *params, int32_t param_count)
3439 {
3440     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetIgnoreWalkbehinds);
3441 }
3442 
3443 // int (CharacterInfo *chaa)
Sc_Character_GetLoop(void * self,const RuntimeScriptValue * params,int32_t param_count)3444 RuntimeScriptValue Sc_Character_GetLoop(void *self, const RuntimeScriptValue *params, int32_t param_count)
3445 {
3446     API_OBJCALL_INT(CharacterInfo, Character_GetLoop);
3447 }
3448 
3449 // void (CharacterInfo *chaa, int newval)
Sc_Character_SetLoop(void * self,const RuntimeScriptValue * params,int32_t param_count)3450 RuntimeScriptValue Sc_Character_SetLoop(void *self, const RuntimeScriptValue *params, int32_t param_count)
3451 {
3452     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetLoop);
3453 }
3454 
3455 // void (CharacterInfo *chaa, int yesorno)
Sc_Character_SetManualScaling(void * self,const RuntimeScriptValue * params,int32_t param_count)3456 RuntimeScriptValue Sc_Character_SetManualScaling(void *self, const RuntimeScriptValue *params, int32_t param_count)
3457 {
3458     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetManualScaling);
3459 }
3460 
3461 // int (CharacterInfo *chaa)
Sc_Character_GetMovementLinkedToAnimation(void * self,const RuntimeScriptValue * params,int32_t param_count)3462 RuntimeScriptValue Sc_Character_GetMovementLinkedToAnimation(void *self, const RuntimeScriptValue *params, int32_t param_count)
3463 {
3464     API_OBJCALL_INT(CharacterInfo, Character_GetMovementLinkedToAnimation);
3465 }
3466 
3467 // void (CharacterInfo *chaa, int yesorno)
Sc_Character_SetMovementLinkedToAnimation(void * self,const RuntimeScriptValue * params,int32_t param_count)3468 RuntimeScriptValue Sc_Character_SetMovementLinkedToAnimation(void *self, const RuntimeScriptValue *params, int32_t param_count)
3469 {
3470     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetMovementLinkedToAnimation);
3471 }
3472 
3473 // int (CharacterInfo *chaa)
Sc_Character_GetMoving(void * self,const RuntimeScriptValue * params,int32_t param_count)3474 RuntimeScriptValue Sc_Character_GetMoving(void *self, const RuntimeScriptValue *params, int32_t param_count)
3475 {
3476     API_OBJCALL_INT(CharacterInfo, Character_GetMoving);
3477 }
3478 
3479 // int (CharacterInfo *chaa)
Sc_Character_GetDestinationX(void * self,const RuntimeScriptValue * params,int32_t param_count)3480 RuntimeScriptValue Sc_Character_GetDestinationX(void *self, const RuntimeScriptValue *params, int32_t param_count)
3481 {
3482     API_OBJCALL_INT(CharacterInfo, Character_GetDestinationX);
3483 }
3484 
3485 // int (CharacterInfo *chaa)
Sc_Character_GetDestinationY(void * self,const RuntimeScriptValue * params,int32_t param_count)3486 RuntimeScriptValue Sc_Character_GetDestinationY(void *self, const RuntimeScriptValue *params, int32_t param_count)
3487 {
3488     API_OBJCALL_INT(CharacterInfo, Character_GetDestinationY);
3489 }
3490 
3491 // const char* (CharacterInfo *chaa)
Sc_Character_GetName(void * self,const RuntimeScriptValue * params,int32_t param_count)3492 RuntimeScriptValue Sc_Character_GetName(void *self, const RuntimeScriptValue *params, int32_t param_count)
3493 {
3494     API_OBJCALL_OBJ(CharacterInfo, const char, myScriptStringImpl, Character_GetName);
3495 }
3496 
3497 // void (CharacterInfo *chaa, const char *newName)
Sc_Character_SetName(void * self,const RuntimeScriptValue * params,int32_t param_count)3498 RuntimeScriptValue Sc_Character_SetName(void *self, const RuntimeScriptValue *params, int32_t param_count)
3499 {
3500     API_OBJCALL_VOID_POBJ(CharacterInfo, Character_SetName, const char);
3501 }
3502 
3503 // int (CharacterInfo *chaa)
Sc_Character_GetNormalView(void * self,const RuntimeScriptValue * params,int32_t param_count)3504 RuntimeScriptValue Sc_Character_GetNormalView(void *self, const RuntimeScriptValue *params, int32_t param_count)
3505 {
3506     API_OBJCALL_INT(CharacterInfo, Character_GetNormalView);
3507 }
3508 
3509 // int (CharacterInfo *chaa)
Sc_Character_GetPreviousRoom(void * self,const RuntimeScriptValue * params,int32_t param_count)3510 RuntimeScriptValue Sc_Character_GetPreviousRoom(void *self, const RuntimeScriptValue *params, int32_t param_count)
3511 {
3512     API_OBJCALL_INT(CharacterInfo, Character_GetPreviousRoom);
3513 }
3514 
3515 // int (CharacterInfo *chaa)
Sc_Character_GetRoom(void * self,const RuntimeScriptValue * params,int32_t param_count)3516 RuntimeScriptValue Sc_Character_GetRoom(void *self, const RuntimeScriptValue *params, int32_t param_count)
3517 {
3518     API_OBJCALL_INT(CharacterInfo, Character_GetRoom);
3519 }
3520 
3521 // int (CharacterInfo *chaa)
Sc_Character_GetScaleMoveSpeed(void * self,const RuntimeScriptValue * params,int32_t param_count)3522 RuntimeScriptValue Sc_Character_GetScaleMoveSpeed(void *self, const RuntimeScriptValue *params, int32_t param_count)
3523 {
3524     API_OBJCALL_INT(CharacterInfo, Character_GetScaleMoveSpeed);
3525 }
3526 
3527 // void (CharacterInfo *chaa, int yesorno)
Sc_Character_SetScaleMoveSpeed(void * self,const RuntimeScriptValue * params,int32_t param_count)3528 RuntimeScriptValue Sc_Character_SetScaleMoveSpeed(void *self, const RuntimeScriptValue *params, int32_t param_count)
3529 {
3530     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetScaleMoveSpeed);
3531 }
3532 
3533 // int (CharacterInfo *chaa)
Sc_Character_GetScaleVolume(void * self,const RuntimeScriptValue * params,int32_t param_count)3534 RuntimeScriptValue Sc_Character_GetScaleVolume(void *self, const RuntimeScriptValue *params, int32_t param_count)
3535 {
3536     API_OBJCALL_INT(CharacterInfo, Character_GetScaleVolume);
3537 }
3538 
3539 // void (CharacterInfo *chaa, int yesorno)
Sc_Character_SetScaleVolume(void * self,const RuntimeScriptValue * params,int32_t param_count)3540 RuntimeScriptValue Sc_Character_SetScaleVolume(void *self, const RuntimeScriptValue *params, int32_t param_count)
3541 {
3542     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetScaleVolume);
3543 }
3544 
3545 // int (CharacterInfo *chaa)
Sc_Character_GetScaling(void * self,const RuntimeScriptValue * params,int32_t param_count)3546 RuntimeScriptValue Sc_Character_GetScaling(void *self, const RuntimeScriptValue *params, int32_t param_count)
3547 {
3548     API_OBJCALL_INT(CharacterInfo, Character_GetScaling);
3549 }
3550 
3551 // void (CharacterInfo *chaa, int zoomlevel)
Sc_Character_SetScaling(void * self,const RuntimeScriptValue * params,int32_t param_count)3552 RuntimeScriptValue Sc_Character_SetScaling(void *self, const RuntimeScriptValue *params, int32_t param_count)
3553 {
3554     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetScaling);
3555 }
3556 
3557 // int (CharacterInfo *chaa)
Sc_Character_GetSolid(void * self,const RuntimeScriptValue * params,int32_t param_count)3558 RuntimeScriptValue Sc_Character_GetSolid(void *self, const RuntimeScriptValue *params, int32_t param_count)
3559 {
3560     API_OBJCALL_INT(CharacterInfo, Character_GetSolid);
3561 }
3562 
3563 // void (CharacterInfo *chaa, int yesorno)
Sc_Character_SetSolid(void * self,const RuntimeScriptValue * params,int32_t param_count)3564 RuntimeScriptValue Sc_Character_SetSolid(void *self, const RuntimeScriptValue *params, int32_t param_count)
3565 {
3566     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetSolid);
3567 }
3568 
3569 // int (CharacterInfo *chaa)
Sc_Character_GetSpeaking(void * self,const RuntimeScriptValue * params,int32_t param_count)3570 RuntimeScriptValue Sc_Character_GetSpeaking(void *self, const RuntimeScriptValue *params, int32_t param_count)
3571 {
3572     API_OBJCALL_INT(CharacterInfo, Character_GetSpeaking);
3573 }
3574 
3575 // int (CharacterInfo *chaa)
Sc_Character_GetSpeakingFrame(void * self,const RuntimeScriptValue * params,int32_t param_count)3576 RuntimeScriptValue Sc_Character_GetSpeakingFrame(void *self, const RuntimeScriptValue *params, int32_t param_count)
3577 {
3578     API_OBJCALL_INT(CharacterInfo, Character_GetSpeakingFrame);
3579 }
3580 
3581 // int (CharacterInfo *cha)
Sc_GetCharacterSpeechAnimationDelay(void * self,const RuntimeScriptValue * params,int32_t param_count)3582 RuntimeScriptValue Sc_GetCharacterSpeechAnimationDelay(void *self, const RuntimeScriptValue *params, int32_t param_count)
3583 {
3584     API_OBJCALL_INT(CharacterInfo, GetCharacterSpeechAnimationDelay);
3585 }
3586 
3587 // void (CharacterInfo *chaa, int newDelay)
Sc_Character_SetSpeechAnimationDelay(void * self,const RuntimeScriptValue * params,int32_t param_count)3588 RuntimeScriptValue Sc_Character_SetSpeechAnimationDelay(void *self, const RuntimeScriptValue *params, int32_t param_count)
3589 {
3590     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetSpeechAnimationDelay);
3591 }
3592 
3593 // int (CharacterInfo *chaa)
Sc_Character_GetSpeechColor(void * self,const RuntimeScriptValue * params,int32_t param_count)3594 RuntimeScriptValue Sc_Character_GetSpeechColor(void *self, const RuntimeScriptValue *params, int32_t param_count)
3595 {
3596     API_OBJCALL_INT(CharacterInfo, Character_GetSpeechColor);
3597 }
3598 
3599 // void (CharacterInfo *chaa, int ncol)
Sc_Character_SetSpeechColor(void * self,const RuntimeScriptValue * params,int32_t param_count)3600 RuntimeScriptValue Sc_Character_SetSpeechColor(void *self, const RuntimeScriptValue *params, int32_t param_count)
3601 {
3602     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetSpeechColor);
3603 }
3604 
3605 // int (CharacterInfo *chaa)
Sc_Character_GetSpeechView(void * self,const RuntimeScriptValue * params,int32_t param_count)3606 RuntimeScriptValue Sc_Character_GetSpeechView(void *self, const RuntimeScriptValue *params, int32_t param_count)
3607 {
3608     API_OBJCALL_INT(CharacterInfo, Character_GetSpeechView);
3609 }
3610 
3611 // void (CharacterInfo *chaa, int vii)
Sc_Character_SetSpeechView(void * self,const RuntimeScriptValue * params,int32_t param_count)3612 RuntimeScriptValue Sc_Character_SetSpeechView(void *self, const RuntimeScriptValue *params, int32_t param_count)
3613 {
3614     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetSpeechView);
3615 }
3616 
Sc_Character_GetThinking(void * self,const RuntimeScriptValue * params,int32_t param_count)3617 RuntimeScriptValue Sc_Character_GetThinking(void *self, const RuntimeScriptValue *params, int32_t param_count)
3618 {
3619     API_OBJCALL_BOOL(CharacterInfo, Character_GetThinking);
3620 }
3621 
Sc_Character_GetThinkingFrame(void * self,const RuntimeScriptValue * params,int32_t param_count)3622 RuntimeScriptValue Sc_Character_GetThinkingFrame(void *self, const RuntimeScriptValue *params, int32_t param_count)
3623 {
3624     API_OBJCALL_INT(CharacterInfo, Character_GetThinkingFrame);
3625 }
3626 
3627 // int (CharacterInfo *chaa)
Sc_Character_GetThinkView(void * self,const RuntimeScriptValue * params,int32_t param_count)3628 RuntimeScriptValue Sc_Character_GetThinkView(void *self, const RuntimeScriptValue *params, int32_t param_count)
3629 {
3630     API_OBJCALL_INT(CharacterInfo, Character_GetThinkView);
3631 }
3632 
3633 // void (CharacterInfo *chaa, int vii)
Sc_Character_SetThinkView(void * self,const RuntimeScriptValue * params,int32_t param_count)3634 RuntimeScriptValue Sc_Character_SetThinkView(void *self, const RuntimeScriptValue *params, int32_t param_count)
3635 {
3636     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetThinkView);
3637 }
3638 
3639 // int (CharacterInfo *chaa)
Sc_Character_GetTransparency(void * self,const RuntimeScriptValue * params,int32_t param_count)3640 RuntimeScriptValue Sc_Character_GetTransparency(void *self, const RuntimeScriptValue *params, int32_t param_count)
3641 {
3642     API_OBJCALL_INT(CharacterInfo, Character_GetTransparency);
3643 }
3644 
3645 // void (CharacterInfo *chaa, int trans)
Sc_Character_SetTransparency(void * self,const RuntimeScriptValue * params,int32_t param_count)3646 RuntimeScriptValue Sc_Character_SetTransparency(void *self, const RuntimeScriptValue *params, int32_t param_count)
3647 {
3648     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetTransparency);
3649 }
3650 
3651 // int (CharacterInfo *chaa)
Sc_Character_GetTurnBeforeWalking(void * self,const RuntimeScriptValue * params,int32_t param_count)3652 RuntimeScriptValue Sc_Character_GetTurnBeforeWalking(void *self, const RuntimeScriptValue *params, int32_t param_count)
3653 {
3654     API_OBJCALL_INT(CharacterInfo, Character_GetTurnBeforeWalking);
3655 }
3656 
3657 // void (CharacterInfo *chaa, int yesorno)
Sc_Character_SetTurnBeforeWalking(void * self,const RuntimeScriptValue * params,int32_t param_count)3658 RuntimeScriptValue Sc_Character_SetTurnBeforeWalking(void *self, const RuntimeScriptValue *params, int32_t param_count)
3659 {
3660     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetTurnBeforeWalking);
3661 }
3662 
3663 // int (CharacterInfo *chaa)
Sc_Character_GetView(void * self,const RuntimeScriptValue * params,int32_t param_count)3664 RuntimeScriptValue Sc_Character_GetView(void *self, const RuntimeScriptValue *params, int32_t param_count)
3665 {
3666     API_OBJCALL_INT(CharacterInfo, Character_GetView);
3667 }
3668 
3669 // int (CharacterInfo *chaa)
Sc_Character_GetWalkSpeedX(void * self,const RuntimeScriptValue * params,int32_t param_count)3670 RuntimeScriptValue Sc_Character_GetWalkSpeedX(void *self, const RuntimeScriptValue *params, int32_t param_count)
3671 {
3672     API_OBJCALL_INT(CharacterInfo, Character_GetWalkSpeedX);
3673 }
3674 
3675 // int (CharacterInfo *chaa)
Sc_Character_GetWalkSpeedY(void * self,const RuntimeScriptValue * params,int32_t param_count)3676 RuntimeScriptValue Sc_Character_GetWalkSpeedY(void *self, const RuntimeScriptValue *params, int32_t param_count)
3677 {
3678     API_OBJCALL_INT(CharacterInfo, Character_GetWalkSpeedY);
3679 }
3680 
3681 // int (CharacterInfo *chaa)
Sc_Character_GetX(void * self,const RuntimeScriptValue * params,int32_t param_count)3682 RuntimeScriptValue Sc_Character_GetX(void *self, const RuntimeScriptValue *params, int32_t param_count)
3683 {
3684     API_OBJCALL_INT(CharacterInfo, Character_GetX);
3685 }
3686 
3687 // void (CharacterInfo *chaa, int newval)
Sc_Character_SetX(void * self,const RuntimeScriptValue * params,int32_t param_count)3688 RuntimeScriptValue Sc_Character_SetX(void *self, const RuntimeScriptValue *params, int32_t param_count)
3689 {
3690     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetX);
3691 }
3692 
3693 // int (CharacterInfo *chaa)
Sc_Character_GetY(void * self,const RuntimeScriptValue * params,int32_t param_count)3694 RuntimeScriptValue Sc_Character_GetY(void *self, const RuntimeScriptValue *params, int32_t param_count)
3695 {
3696     API_OBJCALL_INT(CharacterInfo, Character_GetY);
3697 }
3698 
3699 // void (CharacterInfo *chaa, int newval)
Sc_Character_SetY(void * self,const RuntimeScriptValue * params,int32_t param_count)3700 RuntimeScriptValue Sc_Character_SetY(void *self, const RuntimeScriptValue *params, int32_t param_count)
3701 {
3702     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetY);
3703 }
3704 
3705 // int (CharacterInfo *chaa)
Sc_Character_GetZ(void * self,const RuntimeScriptValue * params,int32_t param_count)3706 RuntimeScriptValue Sc_Character_GetZ(void *self, const RuntimeScriptValue *params, int32_t param_count)
3707 {
3708     API_OBJCALL_INT(CharacterInfo, Character_GetZ);
3709 }
3710 
3711 // void (CharacterInfo *chaa, int newval)
Sc_Character_SetZ(void * self,const RuntimeScriptValue * params,int32_t param_count)3712 RuntimeScriptValue Sc_Character_SetZ(void *self, const RuntimeScriptValue *params, int32_t param_count)
3713 {
3714     API_OBJCALL_VOID_PINT(CharacterInfo, Character_SetZ);
3715 }
3716 
3717 //=============================================================================
3718 //
3719 // Exclusive API for Plugins
3720 //
3721 //=============================================================================
3722 
3723 // void (CharacterInfo *chaa, const char *texx, ...)
ScPl_Character_Say(CharacterInfo * chaa,const char * texx,...)3724 void ScPl_Character_Say(CharacterInfo *chaa, const char *texx, ...)
3725 {
3726     API_PLUGIN_SCRIPT_SPRINTF(texx);
3727     Character_Say(chaa, scsf_buffer);
3728 }
3729 
3730 // void (CharacterInfo *chaa, const char *texx, ...)
ScPl_Character_Think(CharacterInfo * chaa,const char * texx,...)3731 void ScPl_Character_Think(CharacterInfo *chaa, const char *texx, ...)
3732 {
3733     API_PLUGIN_SCRIPT_SPRINTF(texx);
3734     Character_Think(chaa, scsf_buffer);
3735 }
3736 
RegisterCharacterAPI()3737 void RegisterCharacterAPI()
3738 {
3739     ccAddExternalObjectFunction("Character::AddInventory^2",            Sc_Character_AddInventory);
3740 	ccAddExternalObjectFunction("Character::AddWaypoint^2",             Sc_Character_AddWaypoint);
3741 	ccAddExternalObjectFunction("Character::Animate^5",                 Sc_Character_Animate);
3742 	ccAddExternalObjectFunction("Character::ChangeRoom^3",              Sc_Character_ChangeRoom);
3743     ccAddExternalObjectFunction("Character::ChangeRoom^4",              Sc_Character_ChangeRoomSetLoop);
3744 	ccAddExternalObjectFunction("Character::ChangeRoomAutoPosition^2",  Sc_Character_ChangeRoomAutoPosition);
3745 	ccAddExternalObjectFunction("Character::ChangeView^1",              Sc_Character_ChangeView);
3746 	ccAddExternalObjectFunction("Character::FaceCharacter^2",           Sc_Character_FaceCharacter);
3747 	ccAddExternalObjectFunction("Character::FaceDirection^2",           Sc_Character_FaceDirection);
3748 	ccAddExternalObjectFunction("Character::FaceLocation^3",            Sc_Character_FaceLocation);
3749 	ccAddExternalObjectFunction("Character::FaceObject^2",              Sc_Character_FaceObject);
3750 	ccAddExternalObjectFunction("Character::FollowCharacter^3",         Sc_Character_FollowCharacter);
3751 	ccAddExternalObjectFunction("Character::GetProperty^1",             Sc_Character_GetProperty);
3752 	ccAddExternalObjectFunction("Character::GetPropertyText^2",         Sc_Character_GetPropertyText);
3753 	ccAddExternalObjectFunction("Character::GetTextProperty^1",         Sc_Character_GetTextProperty);
3754     ccAddExternalObjectFunction("Character::SetProperty^2",             Sc_Character_SetProperty);
3755     ccAddExternalObjectFunction("Character::SetTextProperty^2",         Sc_Character_SetTextProperty);
3756 	ccAddExternalObjectFunction("Character::HasInventory^1",            Sc_Character_HasInventory);
3757 	ccAddExternalObjectFunction("Character::IsCollidingWithChar^1",     Sc_Character_IsCollidingWithChar);
3758 	ccAddExternalObjectFunction("Character::IsCollidingWithObject^1",   Sc_Character_IsCollidingWithObject);
3759     ccAddExternalObjectFunction("Character::IsInteractionAvailable^1",  Sc_Character_IsInteractionAvailable);
3760 	ccAddExternalObjectFunction("Character::LockView^1",                Sc_Character_LockView);
3761 	ccAddExternalObjectFunction("Character::LockView^2",                Sc_Character_LockViewEx);
3762 	ccAddExternalObjectFunction("Character::LockViewAligned^3",         Sc_Character_LockViewAligned);
3763 	ccAddExternalObjectFunction("Character::LockViewAligned^4",         Sc_Character_LockViewAlignedEx);
3764 	ccAddExternalObjectFunction("Character::LockViewFrame^3",           Sc_Character_LockViewFrame);
3765 	ccAddExternalObjectFunction("Character::LockViewFrame^4",           Sc_Character_LockViewFrameEx);
3766 	ccAddExternalObjectFunction("Character::LockViewOffset^3",          Sc_Character_LockViewOffset);
3767 	ccAddExternalObjectFunction("Character::LockViewOffset^4",          Sc_Character_LockViewOffsetEx);
3768 	ccAddExternalObjectFunction("Character::LoseInventory^1",           Sc_Character_LoseInventory);
3769 	ccAddExternalObjectFunction("Character::Move^4",                    Sc_Character_Move);
3770 	ccAddExternalObjectFunction("Character::PlaceOnWalkableArea^0",     Sc_Character_PlaceOnWalkableArea);
3771 	ccAddExternalObjectFunction("Character::RemoveTint^0",              Sc_Character_RemoveTint);
3772 	ccAddExternalObjectFunction("Character::RunInteraction^1",          Sc_Character_RunInteraction);
3773 	ccAddExternalObjectFunction("Character::Say^101",                   Sc_Character_Say);
3774 	ccAddExternalObjectFunction("Character::SayAt^4",                   Sc_Character_SayAt);
3775 	ccAddExternalObjectFunction("Character::SayBackground^1",           Sc_Character_SayBackground);
3776 	ccAddExternalObjectFunction("Character::SetAsPlayer^0",             Sc_Character_SetAsPlayer);
3777 	ccAddExternalObjectFunction("Character::SetIdleView^2",             Sc_Character_SetIdleView);
3778     ccAddExternalObjectFunction("Character::SetLightLevel^1",           Sc_Character_SetLightLevel);
3779 	//ccAddExternalObjectFunction("Character::SetOption^2",             Sc_Character_SetOption);
3780 	ccAddExternalObjectFunction("Character::SetWalkSpeed^2",            Sc_Character_SetSpeed);
3781 	ccAddExternalObjectFunction("Character::StopMoving^0",              Sc_Character_StopMoving);
3782 	ccAddExternalObjectFunction("Character::Think^101",                 Sc_Character_Think);
3783 	ccAddExternalObjectFunction("Character::Tint^5",                    Sc_Character_Tint);
3784 	ccAddExternalObjectFunction("Character::UnlockView^0",              Sc_Character_UnlockView);
3785 	ccAddExternalObjectFunction("Character::UnlockView^1",              Sc_Character_UnlockViewEx);
3786 	ccAddExternalObjectFunction("Character::Walk^4",                    Sc_Character_Walk);
3787 	ccAddExternalObjectFunction("Character::WalkStraight^3",            Sc_Character_WalkStraight);
3788 
3789 	ccAddExternalStaticFunction("Character::GetAtScreenXY^2",           Sc_GetCharacterAtLocation);
3790 
3791 	ccAddExternalObjectFunction("Character::get_ActiveInventory",       Sc_Character_GetActiveInventory);
3792 	ccAddExternalObjectFunction("Character::set_ActiveInventory",       Sc_Character_SetActiveInventory);
3793 	ccAddExternalObjectFunction("Character::get_Animating",             Sc_Character_GetAnimating);
3794 	ccAddExternalObjectFunction("Character::get_AnimationSpeed",        Sc_Character_GetAnimationSpeed);
3795 	ccAddExternalObjectFunction("Character::set_AnimationSpeed",        Sc_Character_SetAnimationSpeed);
3796 	ccAddExternalObjectFunction("Character::get_Baseline",              Sc_Character_GetBaseline);
3797 	ccAddExternalObjectFunction("Character::set_Baseline",              Sc_Character_SetBaseline);
3798 	ccAddExternalObjectFunction("Character::get_BlinkInterval",         Sc_Character_GetBlinkInterval);
3799 	ccAddExternalObjectFunction("Character::set_BlinkInterval",         Sc_Character_SetBlinkInterval);
3800 	ccAddExternalObjectFunction("Character::get_BlinkView",             Sc_Character_GetBlinkView);
3801 	ccAddExternalObjectFunction("Character::set_BlinkView",             Sc_Character_SetBlinkView);
3802 	ccAddExternalObjectFunction("Character::get_BlinkWhileThinking",    Sc_Character_GetBlinkWhileThinking);
3803 	ccAddExternalObjectFunction("Character::set_BlinkWhileThinking",    Sc_Character_SetBlinkWhileThinking);
3804 	ccAddExternalObjectFunction("Character::get_BlockingHeight",        Sc_Character_GetBlockingHeight);
3805 	ccAddExternalObjectFunction("Character::set_BlockingHeight",        Sc_Character_SetBlockingHeight);
3806 	ccAddExternalObjectFunction("Character::get_BlockingWidth",         Sc_Character_GetBlockingWidth);
3807 	ccAddExternalObjectFunction("Character::set_BlockingWidth",         Sc_Character_SetBlockingWidth);
3808 	ccAddExternalObjectFunction("Character::get_Clickable",             Sc_Character_GetClickable);
3809 	ccAddExternalObjectFunction("Character::set_Clickable",             Sc_Character_SetClickable);
3810 	ccAddExternalObjectFunction("Character::get_DestinationX",          Sc_Character_GetDestinationX);
3811 	ccAddExternalObjectFunction("Character::get_DestinationY",          Sc_Character_GetDestinationY);
3812 	ccAddExternalObjectFunction("Character::get_DiagonalLoops",         Sc_Character_GetDiagonalWalking);
3813 	ccAddExternalObjectFunction("Character::set_DiagonalLoops",         Sc_Character_SetDiagonalWalking);
3814 	ccAddExternalObjectFunction("Character::get_Frame",                 Sc_Character_GetFrame);
3815 	ccAddExternalObjectFunction("Character::set_Frame",                 Sc_Character_SetFrame);
3816 	ccAddExternalObjectFunction("Character::get_HasExplicitTint",       Sc_Character_GetHasExplicitTint);
3817 	ccAddExternalObjectFunction("Character::get_ID",                    Sc_Character_GetID);
3818 	ccAddExternalObjectFunction("Character::get_IdleView",              Sc_Character_GetIdleView);
3819 	ccAddExternalObjectFunction("Character::geti_InventoryQuantity",    Sc_Character_GetIInventoryQuantity);
3820 	ccAddExternalObjectFunction("Character::seti_InventoryQuantity",    Sc_Character_SetIInventoryQuantity);
3821 	ccAddExternalObjectFunction("Character::get_IgnoreLighting",        Sc_Character_GetIgnoreLighting);
3822 	ccAddExternalObjectFunction("Character::set_IgnoreLighting",        Sc_Character_SetIgnoreLighting);
3823 	ccAddExternalObjectFunction("Character::get_IgnoreScaling",         Sc_Character_GetIgnoreScaling);
3824 	ccAddExternalObjectFunction("Character::set_IgnoreScaling",         Sc_Character_SetIgnoreScaling);
3825 	ccAddExternalObjectFunction("Character::get_IgnoreWalkbehinds",     Sc_Character_GetIgnoreWalkbehinds);
3826 	ccAddExternalObjectFunction("Character::set_IgnoreWalkbehinds",     Sc_Character_SetIgnoreWalkbehinds);
3827 	ccAddExternalObjectFunction("Character::get_Loop",                  Sc_Character_GetLoop);
3828 	ccAddExternalObjectFunction("Character::set_Loop",                  Sc_Character_SetLoop);
3829 	ccAddExternalObjectFunction("Character::get_ManualScaling",         Sc_Character_GetIgnoreScaling);
3830 	ccAddExternalObjectFunction("Character::set_ManualScaling",         Sc_Character_SetManualScaling);
3831 	ccAddExternalObjectFunction("Character::get_MovementLinkedToAnimation",Sc_Character_GetMovementLinkedToAnimation);
3832 	ccAddExternalObjectFunction("Character::set_MovementLinkedToAnimation",Sc_Character_SetMovementLinkedToAnimation);
3833 	ccAddExternalObjectFunction("Character::get_Moving",                Sc_Character_GetMoving);
3834 	ccAddExternalObjectFunction("Character::get_Name",                  Sc_Character_GetName);
3835 	ccAddExternalObjectFunction("Character::set_Name",                  Sc_Character_SetName);
3836 	ccAddExternalObjectFunction("Character::get_NormalView",            Sc_Character_GetNormalView);
3837 	ccAddExternalObjectFunction("Character::get_PreviousRoom",          Sc_Character_GetPreviousRoom);
3838 	ccAddExternalObjectFunction("Character::get_Room",                  Sc_Character_GetRoom);
3839 	ccAddExternalObjectFunction("Character::get_ScaleMoveSpeed",        Sc_Character_GetScaleMoveSpeed);
3840 	ccAddExternalObjectFunction("Character::set_ScaleMoveSpeed",        Sc_Character_SetScaleMoveSpeed);
3841 	ccAddExternalObjectFunction("Character::get_ScaleVolume",           Sc_Character_GetScaleVolume);
3842 	ccAddExternalObjectFunction("Character::set_ScaleVolume",           Sc_Character_SetScaleVolume);
3843 	ccAddExternalObjectFunction("Character::get_Scaling",               Sc_Character_GetScaling);
3844 	ccAddExternalObjectFunction("Character::set_Scaling",               Sc_Character_SetScaling);
3845 	ccAddExternalObjectFunction("Character::get_Solid",                 Sc_Character_GetSolid);
3846 	ccAddExternalObjectFunction("Character::set_Solid",                 Sc_Character_SetSolid);
3847 	ccAddExternalObjectFunction("Character::get_Speaking",              Sc_Character_GetSpeaking);
3848 	ccAddExternalObjectFunction("Character::get_SpeakingFrame",         Sc_Character_GetSpeakingFrame);
3849 	ccAddExternalObjectFunction("Character::get_SpeechAnimationDelay",  Sc_GetCharacterSpeechAnimationDelay);
3850 	ccAddExternalObjectFunction("Character::set_SpeechAnimationDelay",  Sc_Character_SetSpeechAnimationDelay);
3851 	ccAddExternalObjectFunction("Character::get_SpeechColor",           Sc_Character_GetSpeechColor);
3852 	ccAddExternalObjectFunction("Character::set_SpeechColor",           Sc_Character_SetSpeechColor);
3853 	ccAddExternalObjectFunction("Character::get_SpeechView",            Sc_Character_GetSpeechView);
3854 	ccAddExternalObjectFunction("Character::set_SpeechView",            Sc_Character_SetSpeechView);
3855     ccAddExternalObjectFunction("Character::get_Thinking",              Sc_Character_GetThinking);
3856     ccAddExternalObjectFunction("Character::get_ThinkingFrame",         Sc_Character_GetThinkingFrame);
3857 	ccAddExternalObjectFunction("Character::get_ThinkView",             Sc_Character_GetThinkView);
3858 	ccAddExternalObjectFunction("Character::set_ThinkView",             Sc_Character_SetThinkView);
3859 	ccAddExternalObjectFunction("Character::get_Transparency",          Sc_Character_GetTransparency);
3860 	ccAddExternalObjectFunction("Character::set_Transparency",          Sc_Character_SetTransparency);
3861 	ccAddExternalObjectFunction("Character::get_TurnBeforeWalking",     Sc_Character_GetTurnBeforeWalking);
3862 	ccAddExternalObjectFunction("Character::set_TurnBeforeWalking",     Sc_Character_SetTurnBeforeWalking);
3863 	ccAddExternalObjectFunction("Character::get_View",                  Sc_Character_GetView);
3864 	ccAddExternalObjectFunction("Character::get_WalkSpeedX",            Sc_Character_GetWalkSpeedX);
3865 	ccAddExternalObjectFunction("Character::get_WalkSpeedY",            Sc_Character_GetWalkSpeedY);
3866 	ccAddExternalObjectFunction("Character::get_X",                     Sc_Character_GetX);
3867 	ccAddExternalObjectFunction("Character::set_X",                     Sc_Character_SetX);
3868 	ccAddExternalObjectFunction("Character::get_x",                     Sc_Character_GetX);
3869 	ccAddExternalObjectFunction("Character::set_x",                     Sc_Character_SetX);
3870 	ccAddExternalObjectFunction("Character::get_Y",                     Sc_Character_GetY);
3871 	ccAddExternalObjectFunction("Character::set_Y",                     Sc_Character_SetY);
3872 	ccAddExternalObjectFunction("Character::get_y",                     Sc_Character_GetY);
3873 	ccAddExternalObjectFunction("Character::set_y",                     Sc_Character_SetY);
3874 	ccAddExternalObjectFunction("Character::get_Z",                     Sc_Character_GetZ);
3875 	ccAddExternalObjectFunction("Character::set_Z",                     Sc_Character_SetZ);
3876 	ccAddExternalObjectFunction("Character::get_z",                     Sc_Character_GetZ);
3877 	ccAddExternalObjectFunction("Character::set_z",                     Sc_Character_SetZ);
3878 
3879     ccAddExternalObjectFunction("Character::get_HasExplicitLight",      Sc_Character_HasExplicitLight);
3880     ccAddExternalObjectFunction("Character::get_LightLevel",            Sc_Character_GetLightLevel);
3881     ccAddExternalObjectFunction("Character::get_TintBlue",              Sc_Character_GetTintBlue);
3882     ccAddExternalObjectFunction("Character::get_TintGreen",             Sc_Character_GetTintGreen);
3883     ccAddExternalObjectFunction("Character::get_TintRed",               Sc_Character_GetTintRed);
3884     ccAddExternalObjectFunction("Character::get_TintSaturation",        Sc_Character_GetTintSaturation);
3885     ccAddExternalObjectFunction("Character::get_TintLuminance",         Sc_Character_GetTintLuminance);
3886 
3887     /* ----------------------- Registering unsafe exports for plugins -----------------------*/
3888 
3889     ccAddExternalFunctionForPlugin("Character::AddInventory^2",            (void*)Character_AddInventory);
3890     ccAddExternalFunctionForPlugin("Character::AddWaypoint^2",             (void*)Character_AddWaypoint);
3891     ccAddExternalFunctionForPlugin("Character::Animate^5",                 (void*)Character_Animate);
3892     ccAddExternalFunctionForPlugin("Character::ChangeRoom^3",              (void*)Character_ChangeRoom);
3893     ccAddExternalFunctionForPlugin("Character::ChangeRoomAutoPosition^2",  (void*)Character_ChangeRoomAutoPosition);
3894     ccAddExternalFunctionForPlugin("Character::ChangeView^1",              (void*)Character_ChangeView);
3895     ccAddExternalFunctionForPlugin("Character::FaceCharacter^2",           (void*)Character_FaceCharacter);
3896     ccAddExternalFunctionForPlugin("Character::FaceDirection^2",           (void*)Character_FaceDirection);
3897     ccAddExternalFunctionForPlugin("Character::FaceLocation^3",            (void*)Character_FaceLocation);
3898     ccAddExternalFunctionForPlugin("Character::FaceObject^2",              (void*)Character_FaceObject);
3899     ccAddExternalFunctionForPlugin("Character::FollowCharacter^3",         (void*)Character_FollowCharacter);
3900     ccAddExternalFunctionForPlugin("Character::GetProperty^1",             (void*)Character_GetProperty);
3901     ccAddExternalFunctionForPlugin("Character::GetPropertyText^2",         (void*)Character_GetPropertyText);
3902     ccAddExternalFunctionForPlugin("Character::GetTextProperty^1",         (void*)Character_GetTextProperty);
3903     ccAddExternalFunctionForPlugin("Character::HasInventory^1",            (void*)Character_HasInventory);
3904     ccAddExternalFunctionForPlugin("Character::IsCollidingWithChar^1",     (void*)Character_IsCollidingWithChar);
3905     ccAddExternalFunctionForPlugin("Character::IsCollidingWithObject^1",   (void*)Character_IsCollidingWithObject);
3906     ccAddExternalFunctionForPlugin("Character::LockView^1",                (void*)Character_LockView);
3907     ccAddExternalFunctionForPlugin("Character::LockView^2",                (void*)Character_LockViewEx);
3908     ccAddExternalFunctionForPlugin("Character::LockViewAligned^3",         (void*)Character_LockViewAligned);
3909     ccAddExternalFunctionForPlugin("Character::LockViewAligned^4",         (void*)Character_LockViewAlignedEx);
3910     ccAddExternalFunctionForPlugin("Character::LockViewFrame^3",           (void*)Character_LockViewFrame);
3911     ccAddExternalFunctionForPlugin("Character::LockViewFrame^4",           (void*)Character_LockViewFrameEx);
3912     ccAddExternalFunctionForPlugin("Character::LockViewOffset^3",          (void*)Character_LockViewOffset);
3913     ccAddExternalFunctionForPlugin("Character::LockViewOffset^4",          (void*)Character_LockViewOffset);
3914     ccAddExternalFunctionForPlugin("Character::LoseInventory^1",           (void*)Character_LoseInventory);
3915     ccAddExternalFunctionForPlugin("Character::Move^4",                    (void*)Character_Move);
3916     ccAddExternalFunctionForPlugin("Character::PlaceOnWalkableArea^0",     (void*)Character_PlaceOnWalkableArea);
3917     ccAddExternalFunctionForPlugin("Character::RemoveTint^0",              (void*)Character_RemoveTint);
3918     ccAddExternalFunctionForPlugin("Character::RunInteraction^1",          (void*)Character_RunInteraction);
3919     ccAddExternalFunctionForPlugin("Character::Say^101",                   (void*)ScPl_Character_Say);
3920     ccAddExternalFunctionForPlugin("Character::SayAt^4",                   (void*)Character_SayAt);
3921     ccAddExternalFunctionForPlugin("Character::SayBackground^1",           (void*)Character_SayBackground);
3922     ccAddExternalFunctionForPlugin("Character::SetAsPlayer^0",             (void*)Character_SetAsPlayer);
3923     ccAddExternalFunctionForPlugin("Character::SetIdleView^2",             (void*)Character_SetIdleView);
3924     //ccAddExternalFunctionForPlugin("Character::SetOption^2",             (void*)Character_SetOption);
3925     ccAddExternalFunctionForPlugin("Character::SetWalkSpeed^2",            (void*)Character_SetSpeed);
3926     ccAddExternalFunctionForPlugin("Character::StopMoving^0",              (void*)Character_StopMoving);
3927     ccAddExternalFunctionForPlugin("Character::Think^101",                 (void*)ScPl_Character_Think);
3928     ccAddExternalFunctionForPlugin("Character::Tint^5",                    (void*)Character_Tint);
3929     ccAddExternalFunctionForPlugin("Character::UnlockView^0",              (void*)Character_UnlockView);
3930     ccAddExternalFunctionForPlugin("Character::UnlockView^1",              (void*)Character_UnlockViewEx);
3931     ccAddExternalFunctionForPlugin("Character::Walk^4",                    (void*)Character_Walk);
3932     ccAddExternalFunctionForPlugin("Character::WalkStraight^3",            (void*)Character_WalkStraight);
3933     ccAddExternalFunctionForPlugin("Character::GetAtScreenXY^2",           (void*)GetCharacterAtLocation);
3934     ccAddExternalFunctionForPlugin("Character::get_ActiveInventory",       (void*)Character_GetActiveInventory);
3935     ccAddExternalFunctionForPlugin("Character::set_ActiveInventory",       (void*)Character_SetActiveInventory);
3936     ccAddExternalFunctionForPlugin("Character::get_Animating",             (void*)Character_GetAnimating);
3937     ccAddExternalFunctionForPlugin("Character::get_AnimationSpeed",        (void*)Character_GetAnimationSpeed);
3938     ccAddExternalFunctionForPlugin("Character::set_AnimationSpeed",        (void*)Character_SetAnimationSpeed);
3939     ccAddExternalFunctionForPlugin("Character::get_Baseline",              (void*)Character_GetBaseline);
3940     ccAddExternalFunctionForPlugin("Character::set_Baseline",              (void*)Character_SetBaseline);
3941     ccAddExternalFunctionForPlugin("Character::get_BlinkInterval",         (void*)Character_GetBlinkInterval);
3942     ccAddExternalFunctionForPlugin("Character::set_BlinkInterval",         (void*)Character_SetBlinkInterval);
3943     ccAddExternalFunctionForPlugin("Character::get_BlinkView",             (void*)Character_GetBlinkView);
3944     ccAddExternalFunctionForPlugin("Character::set_BlinkView",             (void*)Character_SetBlinkView);
3945     ccAddExternalFunctionForPlugin("Character::get_BlinkWhileThinking",    (void*)Character_GetBlinkWhileThinking);
3946     ccAddExternalFunctionForPlugin("Character::set_BlinkWhileThinking",    (void*)Character_SetBlinkWhileThinking);
3947     ccAddExternalFunctionForPlugin("Character::get_BlockingHeight",        (void*)Character_GetBlockingHeight);
3948     ccAddExternalFunctionForPlugin("Character::set_BlockingHeight",        (void*)Character_SetBlockingHeight);
3949     ccAddExternalFunctionForPlugin("Character::get_BlockingWidth",         (void*)Character_GetBlockingWidth);
3950     ccAddExternalFunctionForPlugin("Character::set_BlockingWidth",         (void*)Character_SetBlockingWidth);
3951     ccAddExternalFunctionForPlugin("Character::get_Clickable",             (void*)Character_GetClickable);
3952     ccAddExternalFunctionForPlugin("Character::set_Clickable",             (void*)Character_SetClickable);
3953     ccAddExternalFunctionForPlugin("Character::get_DestinationX",          (void*)Character_GetDestinationX);
3954     ccAddExternalFunctionForPlugin("Character::get_DestinationY",          (void*)Character_GetDestinationY);
3955     ccAddExternalFunctionForPlugin("Character::get_DiagonalLoops",         (void*)Character_GetDiagonalWalking);
3956     ccAddExternalFunctionForPlugin("Character::set_DiagonalLoops",         (void*)Character_SetDiagonalWalking);
3957     ccAddExternalFunctionForPlugin("Character::get_Frame",                 (void*)Character_GetFrame);
3958     ccAddExternalFunctionForPlugin("Character::set_Frame",                 (void*)Character_SetFrame);
3959     ccAddExternalFunctionForPlugin("Character::get_HasExplicitTint",       (void*)Character_GetHasExplicitTint);
3960     ccAddExternalFunctionForPlugin("Character::get_ID",                    (void*)Character_GetID);
3961     ccAddExternalFunctionForPlugin("Character::get_IdleView",              (void*)Character_GetIdleView);
3962     ccAddExternalFunctionForPlugin("Character::geti_InventoryQuantity",    (void*)Character_GetIInventoryQuantity);
3963     ccAddExternalFunctionForPlugin("Character::seti_InventoryQuantity",    (void*)Character_SetIInventoryQuantity);
3964     ccAddExternalFunctionForPlugin("Character::get_IgnoreLighting",        (void*)Character_GetIgnoreLighting);
3965     ccAddExternalFunctionForPlugin("Character::set_IgnoreLighting",        (void*)Character_SetIgnoreLighting);
3966     ccAddExternalFunctionForPlugin("Character::get_IgnoreScaling",         (void*)Character_GetIgnoreScaling);
3967     ccAddExternalFunctionForPlugin("Character::set_IgnoreScaling",         (void*)Character_SetIgnoreScaling);
3968     ccAddExternalFunctionForPlugin("Character::get_IgnoreWalkbehinds",     (void*)Character_GetIgnoreWalkbehinds);
3969     ccAddExternalFunctionForPlugin("Character::set_IgnoreWalkbehinds",     (void*)Character_SetIgnoreWalkbehinds);
3970     ccAddExternalFunctionForPlugin("Character::get_Loop",                  (void*)Character_GetLoop);
3971     ccAddExternalFunctionForPlugin("Character::set_Loop",                  (void*)Character_SetLoop);
3972     ccAddExternalFunctionForPlugin("Character::get_ManualScaling",         (void*)Character_GetIgnoreScaling);
3973     ccAddExternalFunctionForPlugin("Character::set_ManualScaling",         (void*)Character_SetManualScaling);
3974     ccAddExternalFunctionForPlugin("Character::get_MovementLinkedToAnimation",(void*)Character_GetMovementLinkedToAnimation);
3975     ccAddExternalFunctionForPlugin("Character::set_MovementLinkedToAnimation",(void*)Character_SetMovementLinkedToAnimation);
3976     ccAddExternalFunctionForPlugin("Character::get_Moving",                (void*)Character_GetMoving);
3977     ccAddExternalFunctionForPlugin("Character::get_Name",                  (void*)Character_GetName);
3978     ccAddExternalFunctionForPlugin("Character::set_Name",                  (void*)Character_SetName);
3979     ccAddExternalFunctionForPlugin("Character::get_NormalView",            (void*)Character_GetNormalView);
3980     ccAddExternalFunctionForPlugin("Character::get_PreviousRoom",          (void*)Character_GetPreviousRoom);
3981     ccAddExternalFunctionForPlugin("Character::get_Room",                  (void*)Character_GetRoom);
3982     ccAddExternalFunctionForPlugin("Character::get_ScaleMoveSpeed",        (void*)Character_GetScaleMoveSpeed);
3983     ccAddExternalFunctionForPlugin("Character::set_ScaleMoveSpeed",        (void*)Character_SetScaleMoveSpeed);
3984     ccAddExternalFunctionForPlugin("Character::get_ScaleVolume",           (void*)Character_GetScaleVolume);
3985     ccAddExternalFunctionForPlugin("Character::set_ScaleVolume",           (void*)Character_SetScaleVolume);
3986     ccAddExternalFunctionForPlugin("Character::get_Scaling",               (void*)Character_GetScaling);
3987     ccAddExternalFunctionForPlugin("Character::set_Scaling",               (void*)Character_SetScaling);
3988     ccAddExternalFunctionForPlugin("Character::get_Solid",                 (void*)Character_GetSolid);
3989     ccAddExternalFunctionForPlugin("Character::set_Solid",                 (void*)Character_SetSolid);
3990     ccAddExternalFunctionForPlugin("Character::get_Speaking",              (void*)Character_GetSpeaking);
3991     ccAddExternalFunctionForPlugin("Character::get_SpeakingFrame",         (void*)Character_GetSpeakingFrame);
3992     ccAddExternalFunctionForPlugin("Character::get_SpeechAnimationDelay",  (void*)GetCharacterSpeechAnimationDelay);
3993     ccAddExternalFunctionForPlugin("Character::set_SpeechAnimationDelay",  (void*)Character_SetSpeechAnimationDelay);
3994     ccAddExternalFunctionForPlugin("Character::get_SpeechColor",           (void*)Character_GetSpeechColor);
3995     ccAddExternalFunctionForPlugin("Character::set_SpeechColor",           (void*)Character_SetSpeechColor);
3996     ccAddExternalFunctionForPlugin("Character::get_SpeechView",            (void*)Character_GetSpeechView);
3997     ccAddExternalFunctionForPlugin("Character::set_SpeechView",            (void*)Character_SetSpeechView);
3998     ccAddExternalFunctionForPlugin("Character::get_ThinkView",             (void*)Character_GetThinkView);
3999     ccAddExternalFunctionForPlugin("Character::set_ThinkView",             (void*)Character_SetThinkView);
4000     ccAddExternalFunctionForPlugin("Character::get_Transparency",          (void*)Character_GetTransparency);
4001     ccAddExternalFunctionForPlugin("Character::set_Transparency",          (void*)Character_SetTransparency);
4002     ccAddExternalFunctionForPlugin("Character::get_TurnBeforeWalking",     (void*)Character_GetTurnBeforeWalking);
4003     ccAddExternalFunctionForPlugin("Character::set_TurnBeforeWalking",     (void*)Character_SetTurnBeforeWalking);
4004     ccAddExternalFunctionForPlugin("Character::get_View",                  (void*)Character_GetView);
4005     ccAddExternalFunctionForPlugin("Character::get_WalkSpeedX",            (void*)Character_GetWalkSpeedX);
4006     ccAddExternalFunctionForPlugin("Character::get_WalkSpeedY",            (void*)Character_GetWalkSpeedY);
4007     ccAddExternalFunctionForPlugin("Character::get_X",                     (void*)Character_GetX);
4008     ccAddExternalFunctionForPlugin("Character::set_X",                     (void*)Character_SetX);
4009     ccAddExternalFunctionForPlugin("Character::get_x",                     (void*)Character_GetX);
4010     ccAddExternalFunctionForPlugin("Character::set_x",                     (void*)Character_SetX);
4011     ccAddExternalFunctionForPlugin("Character::get_Y",                     (void*)Character_GetY);
4012     ccAddExternalFunctionForPlugin("Character::set_Y",                     (void*)Character_SetY);
4013     ccAddExternalFunctionForPlugin("Character::get_y",                     (void*)Character_GetY);
4014     ccAddExternalFunctionForPlugin("Character::set_y",                     (void*)Character_SetY);
4015     ccAddExternalFunctionForPlugin("Character::get_Z",                     (void*)Character_GetZ);
4016     ccAddExternalFunctionForPlugin("Character::set_Z",                     (void*)Character_SetZ);
4017     ccAddExternalFunctionForPlugin("Character::get_z",                     (void*)Character_GetZ);
4018     ccAddExternalFunctionForPlugin("Character::set_z",                     (void*)Character_SetZ);
4019 }
4020