1 /**********************************************************************************
2 * Copyright (c) 2008, 2009 Derek Yu and Mossmouth, LLC
3 * Copyright (c) 2018, Ketmar Dark
5 * This file is part of Spelunky.
7 * You can redistribute and/or modify Spelunky, including its source code, under
8 * the terms of the Spelunky User License.
10 * Spelunky is distributed in the hope that it will be entertaining and useful,
11 * but WITHOUT WARRANTY. Please see the Spelunky User License for more details.
13 * The Spelunky User License should be available in "Game Information", which
14 * can be found in the Resource Explorer, or as an external file called COPYING.
15 * If not, please obtain a new copy of Spelunky from <http://spelunkyworld.com/>
17 **********************************************************************************/
18 // ////////////////////////////////////////////////////////////////////////// //
19 // dunno, she is an item in the original code
20 class ObjCharacter : MapObject;
22 int holdXOfs, holdYOfs;
25 // turn them around if they are looking at a wall
26 final void initFixDirection () {
27 if (level.isSolidAtPoint(ix-4, iy+8)) dir = Dir.Right;
28 else if (level.isSolidAtPoint(ix+16+4, iy+8)) dir = Dir.Left;
32 override bool onExplosionTouch (MapObject xplo) {
33 if (invincible) return false;
34 if (xplo.fltx < fltx) xVel = global.randOther(4, 6); else xVel = -global.randOther(4, 6);
37 if (!bloodless && bloodLeft > 0) {
38 scrCreateBlood(ix, iy, 1);
39 if (hp <= 0) --bloodLeft;
41 hp -= global.config.explosionDmg;
42 //if (hp <= 0 && !leavesBody) instanceRemove();
47 // return `false` to do standard weapon processing
48 override bool onTouchedByPlayerWeapon (PlayerPawn plr, PlayerWeapon wpn) {
49 if (heldBy) return false;
50 if (!bloodless && bloodLeft > 0) {
52 scrCreateBlood(ix+8, iy-8, 1);
53 if (hp <= 0) --bloodLeft;
60 override void onBulletHit (ObjBullet bullet) {
61 if (heldBy) heldBy.holdItem = none;
66 xVel = bullet.xVel*0.3;
70 override void fixHoldCoords () {
76 int dx = (heldBy.dir == Dir.Left ? -4 : 4);
77 int dy = (heldBy.status == DUCKING && fabs(heldBy.xVel) < 2 ? 4 : 0);
80 setXY(heldBy.fltx+dx, heldBy.flty+dy);
81 prevFltX = heldBy.prevFltX+dx;
82 prevFltY = heldBy.prevFltY+dy;
84 if (spriteRName) dir = heldBy.dir;
90 // return `true` if item hits the character
91 // this is called after item's event
92 bool onItemHit (MapItem proj) {
97 // return `true` if this entity can be sacrificed
98 override bool canBeSacrificed (MapTile altar) {
103 override bool onSacrificed (MapTile altar) {
104 level.performSacrifice(self, altar);
109 override void onStunnedHitEnemy (MapEnemy enemy) {
110 if (enemy isa EnemyMagmaMan) return;
111 if (enemy.status < STUNNED) enemy.xVel = xVel;
112 enemy.countsAsKill = true;
115 if (enemy.canBeStunned) {
116 enemy.status = STUNNED;
121 enemy.playSound('sndHit');
122 //enemy.xVel = xVel*0.3; // was commented in the original
123 //!if (type == "Arrow" or type == "Fish Bone") instance_destroy();
127 override void onStunnedHitCharacter (ObjCharacter chr) {
128 if (chr.status < STUNNED) chr.xVel = xVel;
129 chr.countsAsKill = true;
132 if (chr isa MonsterDamsel) {
139 //enemy.xVel = xVel*0.3; // was commented in the original
140 //!if (type == "Arrow" or type == "Fish Bone") instance_destroy();
144 override void thinkFrame () {
146 if (status == DEAD && removeCorpse) {
147 if (deathTimer > 0) {
150 if (!bloodless && bloodLeft > 0) scrCreateBlood(ix+8, iy+8, 3);
158 objName = 'BaseCharacter';
160 //setCollisionBounds(-4, -4, 4, 8);
172 removeCorpse = false; // only applies to enemies that have corpses (Caveman, Yeti, etc.)
173 deathTimer = 200; // how many steps after death until corpse is removed
175 canBeHitByBullet = true;
178 activeWhenHeld = true; // for animation
179 spectralWhenHeld = false;