ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/monster.C
(Generate patch)

Comparing deliantra/server/server/monster.C (file contents):
Revision 1.8 by root, Sun Sep 10 15:59:57 2006 UTC vs.
Revision 1.21 by root, Sun Jan 14 23:35:04 2007 UTC

1
2/*
3 * static char *rcsid_monster_c =
4 * "$Id: monster.C,v 1.8 2006/09/10 15:59:57 root Exp $";
5 */
6
7/* 1/*
8 CrossFire, A Multiplayer game for X-windows 2 CrossFire, A Multiplayer game for X-windows
9 3
4 Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
10 Copyright (C) 2002 Mark Wedel & Crossfire Development Team 5 Copyright (C) 2002 Mark Wedel & Crossfire Development Team
11 Copyright (C) 1992 Frank Tore Johansen 6 Copyright (C) 1992 Frank Tore Johansen
12 7
13 This program is free software; you can redistribute it and/or modify 8 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by 9 it under the terms of the GNU General Public License as published by
22 17
23 You should have received a copy of the GNU General Public License 18 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software 19 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 21
27 The authors can be reached via e-mail at crossfire-devel@real-time.com 22 The authors can be reached via e-mail at <crossfire@schmorp.de>
28*/ 23*/
29 24
30#include <global.h> 25#include <global.h>
31#ifndef __CEXTRACT__
32# include <sproto.h> 26#include <sproto.h>
33# include <spells.h> 27#include <spells.h>
34# include <skills.h> 28#include <skills.h>
35#endif
36
37 29
38#define MIN_MON_RADIUS 3 /* minimum monster detection radius */ 30#define MIN_MON_RADIUS 3 /* minimum monster detection radius */
39
40 31
41/* checks npc->enemy and returns that enemy if still valid, 32/* checks npc->enemy and returns that enemy if still valid,
42 * NULL otherwise. 33 * NULL otherwise.
43 * this is map tile aware. 34 * this is map tile aware.
44 * If this returns an enemy, the range vector rv should also be 35 * If this returns an enemy, the range vector rv should also be
121object * 112object *
122find_nearest_living_creature (object *npc) 113find_nearest_living_creature (object *npc)
123{ 114{
124 int i, mflags; 115 int i, mflags;
125 sint16 nx, ny; 116 sint16 nx, ny;
126 mapstruct *m; 117 maptile *m;
127 object *tmp;
128 int search_arr[SIZEOFFREE]; 118 int search_arr[SIZEOFFREE];
129 119
130 get_search_arr (search_arr); 120 get_search_arr (search_arr);
121
131 for (i = 0; i < SIZEOFFREE; i++) 122 for (i = 0; i < SIZEOFFREE; i++)
132 { 123 {
133 /* modified to implement smart searching using search_arr 124 /* modified to implement smart searching using search_arr
134 * guidance array to determine direction of search order 125 * guidance array to determine direction of search order
135 */ 126 */
136 nx = npc->x + freearr_x[search_arr[i]]; 127 nx = npc->x + freearr_x[search_arr[i]];
137 ny = npc->y + freearr_y[search_arr[i]]; 128 ny = npc->y + freearr_y[search_arr[i]];
138 m = npc->map; 129 m = npc->map;
139 130
140 mflags = get_map_flags (m, &m, nx, ny, &nx, &ny); 131 mflags = get_map_flags (m, &m, nx, ny, &nx, &ny);
132
141 if (mflags & P_OUT_OF_MAP) 133 if (mflags & P_OUT_OF_MAP)
142 continue; 134 continue;
143 135
144 if (mflags & P_IS_ALIVE) 136 if (mflags & P_IS_ALIVE)
145 { 137 {
146 tmp = get_map_ob (m, nx, ny); 138 for (object *tmp = m->at (nx, ny).top; tmp; tmp = tmp->below)
147 while (tmp != NULL && !QUERY_FLAG (tmp, FLAG_MONSTER) && !QUERY_FLAG (tmp, FLAG_GENERATOR) && tmp->type != PLAYER) 139 if (tmp->flag [FLAG_MONSTER] || tmp->flag [FLAG_GENERATOR] || tmp->type == PLAYER)
148 tmp = tmp->above;
149
150 if (!tmp)
151 {
152 LOG (llevDebug, "find_nearest_living_creature: map %s (%d,%d) has is_alive set but did not find a monster?\n",
153 m->path, nx, ny);
154 }
155 else
156 {
157 if (can_see_monsterP (m, nx, ny, i)) 140 if (can_see_monsterP (m, nx, ny, i))
158 return tmp; 141 return tmp;
159 } 142 }
160 } /* is something living on this space */
161 } 143 }
162 return NULL; /* nothing found */ 144
145 return 0;
163} 146}
164 147
165 148
166/* Tries to find an enmy for npc. We pass the range vector since 149/* Tries to find an enmy for npc. We pass the range vector since
167 * our caller will find the information useful. 150 * our caller will find the information useful.
175find_enemy (object *npc, rv_vector * rv) 158find_enemy (object *npc, rv_vector * rv)
176{ 159{
177 object *attacker, *tmp = NULL; 160 object *attacker, *tmp = NULL;
178 161
179 attacker = npc->attacked_by; /* save this for later use. This can be a attacker. */ 162 attacker = npc->attacked_by; /* save this for later use. This can be a attacker. */
180 npc->attacked_by = NULL; /* always clear the attacker entry */ 163 npc->attacked_by = 0; /* always clear the attacker entry */
181 164
182 /* if we berserk, we don't care about others - we attack all we can find */ 165 /* if we berserk, we don't care about others - we attack all we can find */
183 if (QUERY_FLAG (npc, FLAG_BERSERK)) 166 if (QUERY_FLAG (npc, FLAG_BERSERK))
184 { 167 {
185 tmp = find_nearest_living_creature (npc); 168 tmp = find_nearest_living_creature (npc);
169
186 if (tmp) 170 if (tmp)
187 get_rangevector (npc, tmp, rv, 0); 171 get_rangevector (npc, tmp, rv, 0);
188 return tmp; 172 return tmp;
189 } 173 }
190 174
200 184
201 /* pet move */ 185 /* pet move */
202 if ((npc->attack_movement & HI4) == PETMOVE) 186 if ((npc->attack_movement & HI4) == PETMOVE)
203 { 187 {
204 tmp = get_pet_enemy (npc, rv); 188 tmp = get_pet_enemy (npc, rv);
189
205 if (tmp) 190 if (tmp)
206 get_rangevector (npc, tmp, rv, 0); 191 get_rangevector (npc, tmp, rv, 0);
192
207 return tmp; 193 return tmp;
208 } 194 }
209 195
210 /* we check our old enemy. */ 196 /* we check our old enemy. */
211 if ((tmp = check_enemy (npc, rv)) == NULL) 197 if (!(tmp = check_enemy (npc, rv)))
212 { 198 {
213 if (attacker) /* if we have an attacker, check him */ 199 if (attacker) /* if we have an attacker, check him */
214 { 200 {
215 /* we want be sure this is the right one! */ 201 /* TODO: thats not finished */
216 if (attacker->count == npc->attacked_by_count) 202 /* we don't want a fight evil vs evil or good against non evil */
203
204 if (QUERY_FLAG (npc, FLAG_NEUTRAL) || QUERY_FLAG (attacker, FLAG_NEUTRAL) || /* neutral */
205 (QUERY_FLAG (npc, FLAG_FRIENDLY) && QUERY_FLAG (attacker, FLAG_FRIENDLY)) ||
206 (!QUERY_FLAG (npc, FLAG_FRIENDLY) && (!QUERY_FLAG (attacker, FLAG_FRIENDLY) && attacker->type != PLAYER)))
207 CLEAR_FLAG (npc, FLAG_SLEEP); /* skip it, but lets wakeup */
208 else if (on_same_map (npc, attacker)) /* thats the only thing we must know... */
217 { 209 {
218 /* TODO: thats not finished */
219 /* we don't want a fight evil vs evil or good against non evil */
220
221 if (QUERY_FLAG (npc, FLAG_NEUTRAL) || QUERY_FLAG (attacker, FLAG_NEUTRAL) || /* neutral */
222 (QUERY_FLAG (npc, FLAG_FRIENDLY) && QUERY_FLAG (attacker, FLAG_FRIENDLY)) ||
223 (!QUERY_FLAG (npc, FLAG_FRIENDLY) && (!QUERY_FLAG (attacker, FLAG_FRIENDLY) && attacker->type != PLAYER)))
224 CLEAR_FLAG (npc, FLAG_SLEEP); /* skip it, but lets wakeup */
225 else if (on_same_map (npc, attacker)) /* thats the only thing we must know... */
226 {
227 CLEAR_FLAG (npc, FLAG_SLEEP); /* well, NOW we really should wake up! */ 210 CLEAR_FLAG (npc, FLAG_SLEEP); /* well, NOW we really should wake up! */
228 npc->enemy = attacker; 211 npc->enemy = attacker;
229 return attacker; /* yes, we face our attacker! */ 212 return attacker; /* yes, we face our attacker! */
230 }
231 } 213 }
232 } 214 }
233 215
234 /* we have no legal enemy or attacker, so we try to target a new one */ 216 /* we have no legal enemy or attacker, so we try to target a new one */
235 if (!QUERY_FLAG (npc, FLAG_UNAGGRESSIVE) && !QUERY_FLAG (npc, FLAG_FRIENDLY) && !QUERY_FLAG (npc, FLAG_NEUTRAL)) 217 if (!QUERY_FLAG (npc, FLAG_UNAGGRESSIVE) && !QUERY_FLAG (npc, FLAG_FRIENDLY) && !QUERY_FLAG (npc, FLAG_NEUTRAL))
326 oph = oph->head; 308 oph = oph->head;
327 309
328 if (QUERY_FLAG (op, FLAG_NO_ATTACK)) /* we never ever attack */ 310 if (QUERY_FLAG (op, FLAG_NO_ATTACK)) /* we never ever attack */
329 enemy = op->enemy = NULL; 311 enemy = op->enemy = NULL;
330 else if ((enemy = find_enemy (op, &rv))) 312 else if ((enemy = find_enemy (op, &rv)))
331 {
332 /* we have an enemy, just tell him we want him dead */ 313 /* we have an enemy, just tell him we want him dead */
333 enemy->attacked_by = op; /* our ptr */ 314 enemy->attacked_by = op; /* our ptr */
334 enemy->attacked_by_count = op->count; /* our tag */
335 }
336 315
337 /* generate hp, if applicable */ 316 /* generate hp, if applicable */
338 if (op->stats.Con > 0 && op->stats.hp < op->stats.maxhp) 317 if (op->stats.Con > 0 && op->stats.hp < op->stats.maxhp)
339 { 318 {
340 319
408 /* If we don't have an enemy, do special movement or the like */ 387 /* If we don't have an enemy, do special movement or the like */
409 if (!enemy) 388 if (!enemy)
410 { 389 {
411 if (QUERY_FLAG (op, FLAG_ONLY_ATTACK)) 390 if (QUERY_FLAG (op, FLAG_ONLY_ATTACK))
412 { 391 {
413 remove_ob (op); 392 op->destroy ();
414 free_object (op);
415 return 1; 393 return 1;
416 } 394 }
417 395
418 /* Probably really a bug for a creature to have both 396 /* Probably really a bug for a creature to have both
419 * stand still and a movement type set. 397 * stand still and a movement type set.
468 } /* stand still */ 446 } /* stand still */
469 return 0; 447 return 0;
470 } /* no enemy */ 448 } /* no enemy */
471 449
472 /* We have an enemy. Block immediately below is for pets */ 450 /* We have an enemy. Block immediately below is for pets */
473 if ((op->attack_movement & HI4) == PETMOVE && (owner = get_owner (op)) != NULL && !on_same_map (op, owner)) 451 if ((op->attack_movement & HI4) == PETMOVE && (owner = op->owner) != NULL && !on_same_map (op, owner))
474 return follow_owner (op, owner); 452 return follow_owner (op, owner);
475 453
476 /* doppleganger code to change monster facing to that of the nearest 454 /* doppleganger code to change monster facing to that of the nearest
477 * player. Hmm. The code is here, but no monster in the current 455 * player. Hmm. The code is here, but no monster in the current
478 * arch set uses it. 456 * arch set uses it.
677 if (QUERY_FLAG (part, FLAG_FREED)) /* Might be freed by ghost-attack or hit-back */ 655 if (QUERY_FLAG (part, FLAG_FREED)) /* Might be freed by ghost-attack or hit-back */
678 return 1; 656 return 1;
679 657
680 if (QUERY_FLAG (op, FLAG_ONLY_ATTACK)) 658 if (QUERY_FLAG (op, FLAG_ONLY_ATTACK))
681 { 659 {
682 remove_ob (op); 660 op->remove ();
683 free_object (op); 661 op->destroy ();
684 return 1; 662 return 1;
685 } 663 }
686 return 0; 664 return 0;
687} 665}
688 666
799 * other monsters) 777 * other monsters)
800 */ 778 */
801 if (!(dir = path_to_player (part, pl, 0))) 779 if (!(dir = path_to_player (part, pl, 0)))
802 return 0; 780 return 0;
803 781
804 if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = get_owner (head)) != NULL) 782 if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = head->owner) != NULL)
805 { 783 {
806 get_rangevector (head, owner, &rv1, 0x1); 784 get_rangevector (head, owner, &rv1, 0x1);
807 if (dirdiff (dir, rv1.direction) < 2) 785 if (dirdiff (dir, rv1.direction) < 2)
808 { 786 {
809 return 0; /* Might hit owner with spell */ 787 return 0; /* Might hit owner with spell */
876 * other monsters) 854 * other monsters)
877 */ 855 */
878 if (!(dir = path_to_player (part, pl, 0))) 856 if (!(dir = path_to_player (part, pl, 0)))
879 return 0; 857 return 0;
880 858
881 if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = get_owner (head)) != NULL) 859 if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = head->owner) != NULL)
882 { 860 {
883 get_rangevector (head, owner, &rv1, 0x1); 861 get_rangevector (head, owner, &rv1, 0x1);
884 if (dirdiff (dir, rv1.direction) < 2) 862 if (dirdiff (dir, rv1.direction) < 2)
885 { 863 {
886 return 0; /* Might hit owner with spell */ 864 return 0; /* Might hit owner with spell */
927 object *skill, *owner; 905 object *skill, *owner;
928 906
929 if (!(dir = path_to_player (part, pl, 0))) 907 if (!(dir = path_to_player (part, pl, 0)))
930 return 0; 908 return 0;
931 909
932 if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = get_owner (head)) != NULL) 910 if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = head->owner) != NULL)
933 { 911 {
934 int dir2 = find_dir_2 (head->x - owner->x, head->y - owner->y); 912 int dir2 = find_dir_2 (head->x - owner->x, head->y - owner->y);
935 913
936 if (dirdiff (dir, dir2) < 1) 914 if (dirdiff (dir, dir2) < 1)
937 return 0; /* Might hit owner with skill -thrown rocks for example ? */ 915 return 0; /* Might hit owner with skill -thrown rocks for example ? */
971 int at_least_one = 0; 949 int at_least_one = 0;
972 950
973 if (!(dir = path_to_player (part, pl, 0))) 951 if (!(dir = path_to_player (part, pl, 0)))
974 return 0; 952 return 0;
975 953
976 if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = get_owner (head)) != NULL) 954 if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = head->owner) != NULL)
977 { 955 {
978 int dir2 = find_dir_2 (head->x - owner->x, head->y - owner->y); 956 int dir2 = find_dir_2 (head->x - owner->x, head->y - owner->y);
979 957
980 if (dirdiff (dir, dir2) < 2) 958 if (dirdiff (dir, dir2) < 2)
981 return 0; /* Might hit owner with spell */ 959 return 0; /* Might hit owner with spell */
998 { 976 {
999 if (wand->arch) 977 if (wand->arch)
1000 { 978 {
1001 CLEAR_FLAG (wand, FLAG_ANIMATE); 979 CLEAR_FLAG (wand, FLAG_ANIMATE);
1002 wand->face = wand->arch->clone.face; 980 wand->face = wand->arch->clone.face;
1003 wand->speed = 0; 981 wand->set_speed (0);
1004 update_ob_speed (wand);
1005 } 982 }
1006 } 983 }
1007 /* Success */ 984 /* Success */
1008 return 1; 985 return 1;
1009 } 986 }
1042 if (!(dir = path_to_player (part, pl, 0))) 1019 if (!(dir = path_to_player (part, pl, 0)))
1043 return 0; 1020 return 0;
1044 if (QUERY_FLAG (head, FLAG_CONFUSED)) 1021 if (QUERY_FLAG (head, FLAG_CONFUSED))
1045 dir = absdir (dir + RANDOM () % 3 + RANDOM () % 3 - 2); 1022 dir = absdir (dir + RANDOM () % 3 + RANDOM () % 3 - 2);
1046 1023
1047 if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = get_owner (head)) != NULL) 1024 if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = head->owner) != NULL)
1048 { 1025 {
1049 int dir2 = find_dir_2 (head->x - owner->x, head->y - owner->y); 1026 int dir2 = find_dir_2 (head->x - owner->x, head->y - owner->y);
1050 1027
1051 if (dirdiff (dir, dir2) < 1) 1028 if (dirdiff (dir, dir2) < 1)
1052 return 0; /* Might hit owner with arrow */ 1029 return 0; /* Might hit owner with arrow */
1157 1134
1158void 1135void
1159monster_check_pickup (object *monster) 1136monster_check_pickup (object *monster)
1160{ 1137{
1161 object *tmp, *next; 1138 object *tmp, *next;
1162 int next_tag;
1163 1139
1164 for (tmp = monster->below; tmp != NULL; tmp = next) 1140 for (tmp = monster->below; tmp != NULL; tmp = next)
1165 { 1141 {
1166 next = tmp->below; 1142 next = tmp->below;
1167 next_tag = next ? next->count : 0;
1168 if (monster_can_pick (monster, tmp)) 1143 if (monster_can_pick (monster, tmp))
1169 { 1144 {
1170 remove_ob (tmp); 1145 tmp->remove ();
1171 tmp = insert_ob_in_ob (tmp, monster); 1146 tmp = insert_ob_in_ob (tmp, monster);
1172 (void) monster_check_apply (monster, tmp); 1147 (void) monster_check_apply (monster, tmp);
1173 } 1148 }
1174 /* We could try to re-establish the cycling, of the space, but probably 1149 /* We could try to re-establish the cycling, of the space, but probably
1175 * not a big deal to just bail out. 1150 * not a big deal to just bail out.
1176 */ 1151 */
1177 if (next && was_destroyed (next, next_tag)) 1152 if (next && next->destroyed ())
1178 return; 1153 return;
1179 } 1154 }
1180} 1155}
1181 1156
1182/* 1157/*
1365 /* Don't use it right now */ 1340 /* Don't use it right now */
1366 return; 1341 return;
1367 } 1342 }
1368 else if (item->type == WEAPON) 1343 else if (item->type == WEAPON)
1369 flag = check_good_weapon (mon, item); 1344 flag = check_good_weapon (mon, item);
1370 else if (IS_ARMOR (item)) 1345 else if (item->is_armor ())
1371 flag = check_good_armour (mon, item); 1346 flag = check_good_armour (mon, item);
1372 /* Should do something more, like make sure this is a better item */ 1347 /* Should do something more, like make sure this is a better item */
1373 else if (item->type == RING) 1348 else if (item->type == RING)
1374 flag = 1; 1349 flag = 1;
1375 else if (item->type == WAND || item->type == ROD || item->type == HORN) 1350 else if (item->type == WAND || item->type == ROD || item->type == HORN)
1433npc_call_help (object *op) 1408npc_call_help (object *op)
1434{ 1409{
1435 int x, y, mflags; 1410 int x, y, mflags;
1436 object *npc; 1411 object *npc;
1437 sint16 sx, sy; 1412 sint16 sx, sy;
1438 mapstruct *m; 1413 maptile *m;
1439 1414
1440 for (x = -3; x < 4; x++) 1415 for (x = -3; x < 4; x++)
1441 for (y = -3; y < 4; y++) 1416 for (y = -3; y < 4; y++)
1442 { 1417 {
1443 m = op->map; 1418 m = op->map;
1446 mflags = get_map_flags (m, &m, sx, sy, &sx, &sy); 1421 mflags = get_map_flags (m, &m, sx, sy, &sx, &sy);
1447 /* If nothing alive on this space, no need to search the space. */ 1422 /* If nothing alive on this space, no need to search the space. */
1448 if ((mflags & P_OUT_OF_MAP) || !(mflags & P_IS_ALIVE)) 1423 if ((mflags & P_OUT_OF_MAP) || !(mflags & P_IS_ALIVE))
1449 continue; 1424 continue;
1450 1425
1451 for (npc = get_map_ob (m, sx, sy); npc != NULL; npc = npc->above) 1426 for (npc = GET_MAP_OB (m, sx, sy); npc != NULL; npc = npc->above)
1452 if (QUERY_FLAG (npc, FLAG_ALIVE) && QUERY_FLAG (npc, FLAG_UNAGGRESSIVE)) 1427 if (QUERY_FLAG (npc, FLAG_ALIVE) && QUERY_FLAG (npc, FLAG_UNAGGRESSIVE))
1453 npc->enemy = op->enemy; 1428 npc->enemy = op->enemy;
1454 } 1429 }
1455} 1430}
1456 1431
1619 if (move_object (ob, ob->move_status = RANDOM () % 8 + 1)) 1594 if (move_object (ob, ob->move_status = RANDOM () % 8 + 1))
1620 return; 1595 return;
1621} 1596}
1622 1597
1623void 1598void
1624check_earthwalls (object *op, mapstruct *m, int x, int y) 1599check_earthwalls (object *op, maptile *m, int x, int y)
1625{ 1600{
1626 object *tmp; 1601 object *tmp;
1627 1602
1628 for (tmp = get_map_ob (m, x, y); tmp != NULL; tmp = tmp->above) 1603 for (tmp = GET_MAP_OB (m, x, y); tmp != NULL; tmp = tmp->above)
1629 { 1604 {
1630 if (tmp->type == EARTHWALL) 1605 if (tmp->type == EARTHWALL)
1631 { 1606 {
1632 hit_player (tmp, op->stats.dam, op, AT_PHYSICAL, 1); 1607 hit_player (tmp, op->stats.dam, op, AT_PHYSICAL, 1);
1633 return; 1608 return;
1634 } 1609 }
1635 } 1610 }
1636} 1611}
1637 1612
1638void 1613void
1639check_doors (object *op, mapstruct *m, int x, int y) 1614check_doors (object *op, maptile *m, int x, int y)
1640{ 1615{
1641 object *tmp; 1616 object *tmp;
1642 1617
1643 for (tmp = get_map_ob (m, x, y); tmp != NULL; tmp = tmp->above) 1618 for (tmp = GET_MAP_OB (m, x, y); tmp != NULL; tmp = tmp->above)
1644 { 1619 {
1645 if (tmp->type == DOOR) 1620 if (tmp->type == DOOR)
1646 { 1621 {
1647 hit_player (tmp, 1000, op, AT_PHYSICAL, 1); 1622 hit_player (tmp, 1000, op, AT_PHYSICAL, 1);
1648 return; 1623 return;
1847 1822
1848int 1823int
1849stand_in_light (object *op) 1824stand_in_light (object *op)
1850{ 1825{
1851 sint16 nx, ny; 1826 sint16 nx, ny;
1852 mapstruct *m; 1827 maptile *m;
1853 1828
1854 1829
1855 if (!op) 1830 if (!op)
1856 return 0; 1831 return 0;
1857 if (op->glow_radius > 0) 1832 if (op->glow_radius > 0)

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines