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

Comparing deliantra/server/socket/item.C (file contents):
Revision 1.5 by root, Sun Sep 10 13:43:33 2006 UTC vs.
Revision 1.13 by root, Thu Dec 14 00:13:26 2006 UTC

1
2/*
3 * static char *rcsid_item_c =
4 * "$Id: item.C,v 1.5 2006/09/10 13:43:33 root Exp $";
5 */
6
7/* 1/*
8 CrossFire, A Multiplayer game for X-windows 2 CrossFire, A Multiplayer game for X-windows
9 3
10 Copyright (C) 2002 Mark Wedel & Crossfire Development Team 4 Copyright (C) 2002 Mark Wedel & Crossfire Development Team
11 Copyright (C) 1992 Frank Tore Johansen 5 Copyright (C) 1992 Frank Tore Johansen
22 16
23 You should have received a copy of the GNU General Public License 17 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software 18 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 20
27 The author can be reached via e-mail to crossfire-devel@real-time.com 21 The author can be reached via e-mail to <crossfire@schmorp.de>
28*/ 22*/
29 23
30/** 24/**
31 * \file 25 * \file
32 * Client/server logic. 26 * Client/server logic.
141/* Used in the send_look to put object head into SockList 135/* Used in the send_look to put object head into SockList
142 * sl for socket ns. Need socket to know if we need to send 136 * sl for socket ns. Need socket to know if we need to send
143 * animation of face to the client. 137 * animation of face to the client.
144 */ 138 */
145static void 139static void
146add_object_to_socklist (NewSocket * ns, SockList * sl, object *head) 140add_object_to_socklist (NewSocket &ns, SockList &sl, object *head)
147{ 141{
148 int flags, len, anim_speed; 142 int flags, len, anim_speed;
149 char item_n[MAX_BUF]; 143 char item_n[MAX_BUF];
150 const char *item_p; 144 const char *item_p;
151 145
152 flags = query_flags (head); 146 flags = query_flags (head);
153 if (QUERY_FLAG (head, FLAG_NO_PICK)) 147 if (QUERY_FLAG (head, FLAG_NO_PICK))
154 flags |= F_NOPICK; 148 flags |= F_NOPICK;
155 149
156 if (!(ns->faces_sent[head->face->number] & NS_FACESENT_FACE)) 150 if (!(ns.faces_sent[head->face->number] & NS_FACESENT_FACE))
157 esrv_send_face (ns, head->face->number, 0); 151 esrv_send_face (&ns, head->face->number, 0);
158 152
159 if (QUERY_FLAG (head, FLAG_ANIMATE) && !ns->anims_sent[head->animation_id]) 153 if (QUERY_FLAG (head, FLAG_ANIMATE) && !ns.anims_sent[head->animation_id])
160 esrv_send_animation (ns, head->animation_id); 154 esrv_send_animation (&ns, head->animation_id);
161 155
162 SockList_AddInt (sl, head->count); 156 sl << uint32 (head->count)
163 SockList_AddInt (sl, flags); 157 << uint32 (flags)
164 SockList_AddInt (sl, QUERY_FLAG (head, FLAG_NO_PICK) ? -1 : WEIGHT (head)); 158 << uint32 (QUERY_FLAG (head, FLAG_NO_PICK) ? -1 : WEIGHT (head))
165 SockList_AddInt (sl, head->face->number); 159 << uint32 (head->face->number);
166 160
167 if (!head->custom_name) 161 if (!head->custom_name)
168 { 162 {
169 strncpy (item_n, query_base_name (head, 0), 127); 163 strncpy (item_n, query_base_name (head, 0), 127);
170 item_n[127] = 0; 164 item_n[127] = 0;
176 strncpy (item_n, head->custom_name, 127); 170 strncpy (item_n, head->custom_name, 127);
177 item_n[127] = 0; 171 item_n[127] = 0;
178 len = strlen (item_n); 172 len = strlen (item_n);
179 item_p = head->custom_name; 173 item_p = head->custom_name;
180 } 174 }
175
181 strncpy (item_n + len + 1, item_p, 127); 176 strncpy (item_n + len + 1, item_p, 127);
182 item_n[254] = 0; 177 item_n[254] = 0;
183 len += strlen (item_n + 1 + len) + 1; 178 len += strlen (item_n + 1 + len) + 1;
184 SockList_AddChar (sl, (char) len);
185 memcpy (sl->buf + sl->len, item_n, len);
186 sl->len += len;
187 179
188 SockList_AddShort (sl, head->animation_id); 180 sl << data8 (item_n, len)
181 << uint16 (head->animation_id);
182
189 anim_speed = 0; 183 anim_speed = 0;
190 if (QUERY_FLAG (head, FLAG_ANIMATE)) 184 if (QUERY_FLAG (head, FLAG_ANIMATE))
191 { 185 {
192 if (head->anim_speed) 186 if (head->anim_speed)
193 anim_speed = head->anim_speed; 187 anim_speed = head->anim_speed;
198 else if (FABS (head->speed) >= 1.0) 192 else if (FABS (head->speed) >= 1.0)
199 anim_speed = 1; 193 anim_speed = 1;
200 else 194 else
201 anim_speed = (int) (1.0 / FABS (head->speed)); 195 anim_speed = (int) (1.0 / FABS (head->speed));
202 } 196 }
197
203 if (anim_speed > 255) 198 if (anim_speed > 255)
204 anim_speed = 255; 199 anim_speed = 255;
205 } 200 }
206 SockList_AddChar (sl, (char) anim_speed);
207 SockList_AddInt (sl, head->nrof);
208 201
202 sl << uint8 (anim_speed)
203 << uint32 (head->nrof);
204
209 if (ns->itemcmd == 2) 205 if (ns.itemcmd == 2)
210 SockList_AddShort (sl, head->client_type); 206 sl << uint16 (head->client_type);
211 207
212 SET_FLAG (head, FLAG_CLIENT_SENT); 208 SET_FLAG (head, FLAG_CLIENT_SENT);
213} 209}
214 210
215 211
222void 218void
223esrv_draw_look (object *pl) 219esrv_draw_look (object *pl)
224{ 220{
225 object *tmp, *last; 221 object *tmp, *last;
226 int got_one = 0, start_look = 0, end_look = 0; 222 int got_one = 0, start_look = 0, end_look = 0;
227 SockList sl;
228 char buf[MAX_BUF]; 223 char buf[MAX_BUF];
229 224
230 if (!pl->contr->socket.update_look) 225 if (!pl->contr->socket.update_look)
231 { 226 {
232 LOG (llevDebug, "esrv_draw_look called when update_look was not set\n"); 227 LOG (llevDebug, "esrv_draw_look called when update_look was not set\n");
233 return; 228 return;
234 } 229 }
235 else 230 else
236 {
237 pl->contr->socket.update_look = 0; 231 pl->contr->socket.update_look = 0;
238 }
239 232
240 if (QUERY_FLAG (pl, FLAG_REMOVED) || pl->map == NULL || pl->map->in_memory != MAP_IN_MEMORY || out_of_map (pl->map, pl->x, pl->y)) 233 if (QUERY_FLAG (pl, FLAG_REMOVED)
234 || !pl->map
235 || pl->map->in_memory != MAP_IN_MEMORY
236 || out_of_map (pl->map, pl->x, pl->y))
241 return; 237 return;
242 238
243 for (tmp = get_map_ob (pl->map, pl->x, pl->y); tmp && tmp->above; tmp = tmp->above); 239 for (tmp = get_map_ob (pl->map, pl->x, pl->y); tmp && tmp->above; tmp = tmp->above);
244 240
245 sl.buf = (unsigned char *) malloc (MAXSOCKBUF); 241 SockList sl (MAXSOCKBUF);
246 242
247 Write_String_To_Socket (&pl->contr->socket, "delinv 0", strlen ("delinv 0")); 243 Write_String_To_Socket (&pl->contr->socket, "delinv 0", sizeof ("delinv 0") - 1);
244
248 sprintf ((char *) sl.buf, "item%d ", pl->contr->socket.itemcmd); 245 sl.printf ("item%d ", pl->contr->socket.itemcmd);
249 sl.len = strlen ((char *) sl.buf);
250 246
251 SockList_AddInt (&sl, 0); 247 sl << uint32 (0);
252 248
253 if (!(pl->contr->socket.faces_sent[empty_face->number] & NS_FACESENT_FACE)) 249 if (!(pl->contr->socket.faces_sent[empty_face->number] & NS_FACESENT_FACE))
254 esrv_send_face (&pl->contr->socket, empty_face->number, 0); 250 esrv_send_face (&pl->contr->socket, empty_face->number, 0);
255 251
256 if (pl->contr->socket.look_position) 252 if (pl->contr->socket.look_position)
257 { 253 {
258 SockList_AddInt (&sl, 0x80000000 | (pl->contr->socket.look_position - NUM_LOOK_OBJECTS)); 254 sl << uint32 (0x80000000 | (pl->contr->socket.look_position - NUM_LOOK_OBJECTS))
259 SockList_AddInt (&sl, 0); 255 << uint32 (0)
260 SockList_AddInt (&sl, (uint32) - 1); 256 << sint32 (-1)
261 SockList_AddInt (&sl, empty_face->number); 257 << uint32 (empty_face->number);
258
262 sprintf (buf, "Click here to see %d previous items", NUM_LOOK_OBJECTS); 259 sl.printf ("Click here to see %d previous items", NUM_LOOK_OBJECTS);
263 add_stringlen_to_sockbuf (buf, &sl); 260
264 SockList_AddShort (&sl, 0); 261 sl << uint16 (0)
265 SockList_AddChar (&sl, 0); 262 << uint8 (0)
266 SockList_AddInt (&sl, 0); 263 << uint32 (0);
264
267 if (pl->contr->socket.itemcmd == 2) 265 if (pl->contr->socket.itemcmd == 2)
268 SockList_AddShort (&sl, 0); 266 sl << uint16 (0);
269 } 267 }
270 268
271 for (last = NULL; tmp != last; tmp = tmp->below) 269 for (last = NULL; tmp != last; tmp = tmp->below)
272 { 270 {
273 object *head; 271 object *head;
276 { 274 {
277 last = tmp->below; /* assumes double floor mode */ 275 last = tmp->below; /* assumes double floor mode */
278 if (last && QUERY_FLAG (last, FLAG_IS_FLOOR)) 276 if (last && QUERY_FLAG (last, FLAG_IS_FLOOR))
279 last = last->below; 277 last = last->below;
280 } 278 }
279
281 if (LOOK_OBJ (tmp)) 280 if (LOOK_OBJ (tmp))
282 { 281 {
283 if (++start_look < pl->contr->socket.look_position) 282 if (++start_look < pl->contr->socket.look_position)
284 continue; 283 continue;
284
285 end_look++; 285 end_look++;
286
286 if (end_look > NUM_LOOK_OBJECTS) 287 if (end_look > NUM_LOOK_OBJECTS)
287 { 288 {
288 /* What we basically do is make a 'fake' object - when the user applies it, 289 /* What we basically do is make a 'fake' object - when the user applies it,
289 * we notice the special tag the object has, and act accordingly. 290 * we notice the special tag the object has, and act accordingly.
290 */ 291 */
304 if (tmp->head) 305 if (tmp->head)
305 head = tmp->head; 306 head = tmp->head;
306 else 307 else
307 head = tmp; 308 head = tmp;
308 309
309 add_object_to_socklist (&pl->contr->socket, &sl, head); 310 add_object_to_socklist (pl->contr->socket, sl, head);
310 got_one++; 311 got_one++;
311 312
312 if (sl.len >= (MAXSOCKBUF - MAXITEMLEN)) 313 if (sl.len >= (MAXSOCKBUF - MAXITEMLEN))
313 { 314 {
314 Send_With_Handling (&pl->contr->socket, &sl); 315 Send_With_Handling (&pl->contr->socket, &sl);
317 SockList_AddInt (&sl, 0); 318 SockList_AddInt (&sl, 0);
318 got_one = 0; 319 got_one = 0;
319 } 320 }
320 } /* If LOOK_OBJ() */ 321 } /* If LOOK_OBJ() */
321 } 322 }
323
322 if (got_one) 324 if (got_one)
323 Send_With_Handling (&pl->contr->socket, &sl); 325 Send_With_Handling (&pl->contr->socket, &sl);
324 326
325 free (sl.buf); 327 sl.free ();
326} 328}
327 329
328/** 330/**
329 * Sends whole inventory. 331 * Sends whole inventory.
330 */ 332 */
355 else 357 else
356 head = tmp; 358 head = tmp;
357 359
358 if (LOOK_OBJ (head)) 360 if (LOOK_OBJ (head))
359 { 361 {
360 add_object_to_socklist (&pl->contr->socket, &sl, head); 362 add_object_to_socklist (pl->contr->socket, sl, head);
361 363
362 got_one++; 364 got_one++;
363 365
364 /* IT is possible for players to accumulate a huge amount of 366 /* IT is possible for players to accumulate a huge amount of
365 * items (especially with some of the bags out there) to 367 * items (especially with some of the bags out there) to
375 } 377 }
376 } /* If LOOK_OBJ() */ 378 } /* If LOOK_OBJ() */
377 } 379 }
378 if (got_one) 380 if (got_one)
379 Send_With_Handling (&pl->contr->socket, &sl); 381 Send_With_Handling (&pl->contr->socket, &sl);
380 free (sl.buf); 382 sl.free ();
381} 383}
382 384
383/** 385/**
384 * Updates object *op for player *pl. 386 * Updates object *op for player *pl.
385 * 387 *
401 /* we remove the check for op->env, because in theory, the object 403 /* we remove the check for op->env, because in theory, the object
402 * is hopefully in the same place, so the client should preserve 404 * is hopefully in the same place, so the client should preserve
403 * order. 405 * order.
404 */ 406 */
405 } 407 }
408
406 if (!QUERY_FLAG (op, FLAG_CLIENT_SENT)) 409 if (!QUERY_FLAG (op, FLAG_CLIENT_SENT))
407 { 410 {
408 /* FLAG_CLIENT_SENT is debug only. We are using it to see where 411 /* FLAG_CLIENT_SENT is debug only. We are using it to see where
409 * this is happening - we can set a breakpoint here in the debugger 412 * this is happening - we can set a breakpoint here in the debugger
410 * and track back the call. 413 * and track back the call.
411 */ 414 */
412 LOG (llevDebug, "We have not sent item %s (%d)\n", &op->name, op->count); 415 LOG (llevDebug, "We have not sent item %s (%d)\n", &op->name, op->count);
413 } 416 }
417
414 sl.buf = (unsigned char *) malloc (MAXSOCKBUF); 418 sl.buf = (unsigned char *) malloc (MAXSOCKBUF);
415 419
416 strcpy ((char *) sl.buf, "upditem "); 420 strcpy ((char *) sl.buf, "upditem ");
417 sl.len = strlen ((char *) sl.buf); 421 sl.len = strlen ((char *) sl.buf);
418 422
444 { 448 {
445 if (!(pl->contr->socket.faces_sent[op->face->number] & NS_FACESENT_FACE)) 449 if (!(pl->contr->socket.faces_sent[op->face->number] & NS_FACESENT_FACE))
446 esrv_send_face (&pl->contr->socket, op->face->number, 0); 450 esrv_send_face (&pl->contr->socket, op->face->number, 0);
447 SockList_AddInt (&sl, op->face->number); 451 SockList_AddInt (&sl, op->face->number);
448 } 452 }
453
449 if (flags & UPD_NAME) 454 if (flags & UPD_NAME)
450 { 455 {
451 int len; 456 int len;
452 const char *item_p; 457 const char *item_p;
453 char item_n[MAX_BUF]; 458 char item_n[MAX_BUF];
472 len += strlen (item_n + 1 + len) + 1; 477 len += strlen (item_n + 1 + len) + 1;
473 SockList_AddChar (&sl, (char) len); 478 SockList_AddChar (&sl, (char) len);
474 memcpy (sl.buf + sl.len, item_n, len); 479 memcpy (sl.buf + sl.len, item_n, len);
475 sl.len += len; 480 sl.len += len;
476 } 481 }
482
477 if (flags & UPD_ANIM) 483 if (flags & UPD_ANIM)
478 SockList_AddShort (&sl, op->animation_id); 484 SockList_AddShort (&sl, op->animation_id);
479 485
480 if (flags & UPD_ANIMSPEED) 486 if (flags & UPD_ANIMSPEED)
481 { 487 {
501 } 507 }
502 if (flags & UPD_NROF) 508 if (flags & UPD_NROF)
503 SockList_AddInt (&sl, op->nrof); 509 SockList_AddInt (&sl, op->nrof);
504 510
505 Send_With_Handling (&pl->contr->socket, &sl); 511 Send_With_Handling (&pl->contr->socket, &sl);
506 free (sl.buf); 512 sl.free ();
507} 513}
508 514
509/** 515/**
510 * Sends item's info to player. 516 * Sends item's info to player.
511 */ 517 */
538 if (op->head) 544 if (op->head)
539 op = op->head; 545 op = op->head;
540 546
541 SockList_AddInt (&sl, op->env ? op->env->count : 0); 547 SockList_AddInt (&sl, op->env ? op->env->count : 0);
542 548
543 add_object_to_socklist (&pl->contr->socket, &sl, op); 549 add_object_to_socklist (pl->contr->socket, sl, op);
544 550
545 Send_With_Handling (&pl->contr->socket, &sl); 551 Send_With_Handling (&pl->contr->socket, &sl);
546 SET_FLAG (op, FLAG_CLIENT_SENT); 552 SET_FLAG (op, FLAG_CLIENT_SENT);
547 free (sl.buf); 553
554 sl.free ();
548} 555}
549 556
550/** 557/**
551 * Tells the client to delete an item. Uses the item 558 * Tells the client to delete an item. Uses the item
552 * command with a -1 location. 559 * command with a -1 location.
562 strcpy ((char *) sl.buf, "delitem "); 569 strcpy ((char *) sl.buf, "delitem ");
563 sl.len = strlen ((char *) sl.buf); 570 sl.len = strlen ((char *) sl.buf);
564 SockList_AddInt (&sl, tag); 571 SockList_AddInt (&sl, tag);
565 572
566 Send_With_Handling (&pl->socket, &sl); 573 Send_With_Handling (&pl->socket, &sl);
567 free (sl.buf); 574 sl.free ();
568} 575}
569 576
570 577
571/******************************************************************************* 578/*******************************************************************************
572 * 579 *
611 618
612/** Client wants to examine some object. So lets do so. */ 619/** Client wants to examine some object. So lets do so. */
613void 620void
614ExamineCmd (char *buf, int len, player *pl) 621ExamineCmd (char *buf, int len, player *pl)
615{ 622{
616 long tag = atoi (buf); 623 tag_t tag = atoi (buf);
624
625 /* If the high bit is set, player examined a pseudo object. */
626 if (tag & 0x80000000)
627 return;
628
617 object *op = esrv_get_ob_from_count (pl->ob, tag); 629 object *op = esrv_get_ob_from_count (pl->ob, tag);
618 630
619 if (!op) 631 if (!op)
620 { 632 {
621 LOG (llevDebug, "Player '%s' tried to examine the unknown object (%ld)\n", &pl->ob->name, tag); 633 LOG (llevDebug, "Player '%s' tried to examine the unknown object (%ld)\n", &pl->ob->name, tag);
622 return; 634 return;
623 } 635 }
636
624 examine (pl->ob, op); 637 examine (pl->ob, op);
625} 638}
626 639
627/** Client wants to apply some object. Lets do so. */ 640/** Client wants to apply some object. Lets do so. */
628void 641void
629ApplyCmd (char *buf, int len, player *pl) 642ApplyCmd (char *buf, int len, player *pl)
630{ 643{
631 uint32 tag = atoi (buf); 644 tag_t tag = atoi (buf);
632 object *op = esrv_get_ob_from_count (pl->ob, tag);
633 645
634 /* sort of a hack, but if the player saves and the player then manually 646 /* sort of a hack, but if the player saves and the player then manually
635 * applies a savebed (or otherwise tries to do stuff), we run into trouble. 647 * applies a savebed (or otherwise tries to do stuff), we run into trouble.
636 */ 648 */
637 if (QUERY_FLAG (pl->ob, FLAG_REMOVED)) 649 if (QUERY_FLAG (pl->ob, FLAG_REMOVED))
643 pl->socket.look_position = tag & 0x7fffffff; 655 pl->socket.look_position = tag & 0x7fffffff;
644 pl->socket.update_look = 1; 656 pl->socket.update_look = 1;
645 return; 657 return;
646 } 658 }
647 659
660 object *op = esrv_get_ob_from_count (pl->ob, tag);
661
648 if (!op) 662 if (!op)
649 { 663 {
650 LOG (llevDebug, "Player '%s' tried to apply the unknown object (%d)\n", &pl->ob->name, tag); 664 LOG (llevDebug, "Player '%s' tried to apply the unknown object (%d)\n", &pl->ob->name, tag);
651 return; 665 return;
652 } 666 }
667
653 player_apply (pl->ob, op, 0, 0); 668 player_apply (pl->ob, op, 0, 0);
654} 669}
655 670
656/** Client wants to apply some object. Lets do so. */ 671/** Client wants to apply some object. Lets do so. */
657void 672void
658LockItem (uint8 * data, int len, player *pl) 673LockItem (uint8 *data, int len, player *pl)
659{ 674{
660 int flag, tag;
661 object *op;
662
663 flag = data[0]; 675 int flag = data[0];
664 tag = GetInt_String (data + 1); 676 tag_t tag = net_uint32 (data + 1);
665 op = esrv_get_ob_from_count (pl->ob, tag); 677 object *op = esrv_get_ob_from_count (pl->ob, tag);
666 678
667 if (!op) 679 if (!op)
668 { 680 {
669 new_draw_info (NDI_UNIQUE, 0, pl->ob, "Could not find object to lock/unlock"); 681 new_draw_info (NDI_UNIQUE, 0, pl->ob, "Could not find object to lock/unlock");
670 return; 682 return;
671 } 683 }
684
672 if (!flag) 685 if (!flag)
673 CLEAR_FLAG (op, FLAG_INV_LOCKED); 686 CLEAR_FLAG (op, FLAG_INV_LOCKED);
674 else 687 else
675 SET_FLAG (op, FLAG_INV_LOCKED); 688 SET_FLAG (op, FLAG_INV_LOCKED);
689
676 esrv_update_item (UPD_FLAGS, pl->ob, op); 690 esrv_update_item (UPD_FLAGS, pl->ob, op);
677} 691}
678 692
679/** Client wants to apply some object. Lets do so. */ 693/** Client wants to apply some object. Lets do so. */
680void 694void
681MarkItem (uint8 * data, int len, player *pl) 695MarkItem (uint8 * data, int len, player *pl)
682{ 696{
683 int tag; 697 tag_t tag = net_uint32 (data);
684 object *op;
685
686 tag = GetInt_String (data);
687 op = esrv_get_ob_from_count (pl->ob, tag); 698 object *op = esrv_get_ob_from_count (pl->ob, tag);
699
688 if (!op) 700 if (!op)
689 { 701 {
690 new_draw_info (NDI_UNIQUE, 0, pl->ob, "Could not find object to mark"); 702 new_draw_info (NDI_UNIQUE, 0, pl->ob, "Could not find object to mark");
691 return; 703 return;
692 } 704 }
705
693 pl->mark = op; 706 pl->mark = op;
694 pl->mark_count = op->count;
695 new_draw_info_format (NDI_UNIQUE, 0, pl->ob, "Marked item %s", query_name (op)); 707 new_draw_info_format (NDI_UNIQUE, 0, pl->ob, "Marked item %s", query_name (op));
696} 708}
697
698 709
699/** 710/**
700 * look_at prints items on the specified square. 711 * look_at prints items on the specified square.
701 * 712 *
702 * [ removed EARTHWALL check and added check for containers inventory. 713 * [ removed EARTHWALL check and added check for containers inventory.
706look_at (object *op, int dx, int dy) 717look_at (object *op, int dx, int dy)
707{ 718{
708 object *tmp; 719 object *tmp;
709 int flag = 0; 720 int flag = 0;
710 sint16 x, y; 721 sint16 x, y;
711 mapstruct *m; 722 maptile *m;
712 723
713 x = op->x + dx; 724 x = op->x + dx;
714 y = op->y + dy; 725 y = op->y + dy;
715 726
716 if (out_of_map (op->map, x, y)) 727 if (out_of_map (op->map, x, y))

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines